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;
   15mod blink_manager;
   16mod clangd_ext;
   17pub mod code_context_menus;
   18pub mod display_map;
   19mod editor_settings;
   20mod element;
   21mod git;
   22mod highlight_matching_bracket;
   23mod hover_links;
   24pub mod hover_popover;
   25mod indent_guides;
   26mod inlays;
   27pub mod items;
   28mod jsx_tag_auto_close;
   29mod linked_editing_ranges;
   30mod lsp_colors;
   31mod lsp_ext;
   32mod mouse_context_menu;
   33pub mod movement;
   34mod persistence;
   35mod rust_analyzer_ext;
   36pub mod scroll;
   37mod selections_collection;
   38pub mod tasks;
   39
   40#[cfg(test)]
   41mod code_completion_tests;
   42#[cfg(test)]
   43mod edit_prediction_tests;
   44#[cfg(test)]
   45mod editor_tests;
   46mod signature_help;
   47#[cfg(any(test, feature = "test-support"))]
   48pub mod test;
   49
   50pub(crate) use actions::*;
   51pub use display_map::{ChunkRenderer, ChunkRendererContext, DisplayPoint, FoldPlaceholder};
   52pub use edit_prediction::Direction;
   53pub use editor_settings::{
   54    CurrentLineHighlight, DocumentColorsRenderMode, EditorSettings, HideMouseMode,
   55    ScrollBeyondLastLine, ScrollbarAxes, SearchSettings, ShowMinimap,
   56};
   57pub use element::{
   58    CursorLayout, EditorElement, HighlightedRange, HighlightedRangeLine, PointForPosition,
   59};
   60pub use git::blame::BlameRenderer;
   61pub use hover_popover::hover_markdown_style;
   62pub use inlays::Inlay;
   63pub use items::MAX_TAB_TITLE_LEN;
   64pub use lsp::CompletionContext;
   65pub use lsp_ext::lsp_tasks;
   66pub use multi_buffer::{
   67    Anchor, AnchorRangeExt, ExcerptId, ExcerptRange, MultiBuffer, MultiBufferSnapshot, PathKey,
   68    RowInfo, ToOffset, ToPoint,
   69};
   70pub use text::Bias;
   71
   72use ::git::{
   73    Restore,
   74    blame::{BlameEntry, ParsedCommitMessage},
   75    status::FileStatus,
   76};
   77use aho_corasick::AhoCorasick;
   78use anyhow::{Context as _, Result, anyhow};
   79use blink_manager::BlinkManager;
   80use buffer_diff::DiffHunkStatus;
   81use client::{Collaborator, ParticipantIndex, parse_zed_link};
   82use clock::ReplicaId;
   83use code_context_menus::{
   84    AvailableCodeAction, CodeActionContents, CodeActionsItem, CodeActionsMenu, CodeContextMenu,
   85    CompletionsMenu, ContextMenuOrigin,
   86};
   87use collections::{BTreeMap, HashMap, HashSet, VecDeque};
   88use convert_case::{Case, Casing};
   89use dap::TelemetrySpawnLocation;
   90use display_map::*;
   91use edit_prediction::{EditPredictionProvider, EditPredictionProviderHandle};
   92use editor_settings::{GoToDefinitionFallback, Minimap as MinimapSettings};
   93use element::{AcceptEditPredictionBinding, LineWithInvisibles, PositionMap, layout_line};
   94use futures::{
   95    FutureExt, StreamExt as _,
   96    future::{self, Shared, join},
   97    stream::FuturesUnordered,
   98};
   99use fuzzy::{StringMatch, StringMatchCandidate};
  100use git::blame::{GitBlame, GlobalBlameRenderer};
  101use gpui::{
  102    Action, Animation, AnimationExt, AnyElement, App, AppContext, AsyncWindowContext,
  103    AvailableSpace, Background, Bounds, ClickEvent, ClipboardEntry, ClipboardItem, Context,
  104    DispatchPhase, Edges, Entity, EntityInputHandler, EventEmitter, FocusHandle, FocusOutEvent,
  105    Focusable, FontId, FontWeight, Global, HighlightStyle, Hsla, KeyContext, Modifiers,
  106    MouseButton, MouseDownEvent, PaintQuad, ParentElement, Pixels, Render, ScrollHandle,
  107    SharedString, Size, Stateful, Styled, Subscription, Task, TextStyle, TextStyleRefinement,
  108    UTF16Selection, UnderlineStyle, UniformListScrollHandle, WeakEntity, WeakFocusHandle, Window,
  109    div, point, prelude::*, pulsating_between, px, relative, size,
  110};
  111use hover_links::{HoverLink, HoveredLinkState, find_file};
  112use hover_popover::{HoverState, hide_hover};
  113use indent_guides::ActiveIndentGuidesState;
  114use inlays::{InlaySplice, inlay_hints::InlayHintRefreshReason};
  115use itertools::{Either, Itertools};
  116use language::{
  117    AutoindentMode, BlockCommentConfig, BracketMatch, BracketPair, Buffer, BufferRow,
  118    BufferSnapshot, Capability, CharClassifier, CharKind, CharScopeContext, CodeLabel, CursorShape,
  119    DiagnosticEntryRef, DiffOptions, EditPredictionsMode, EditPreview, HighlightedText, IndentKind,
  120    IndentSize, Language, OffsetRangeExt, OutlineItem, Point, Runnable, RunnableRange, Selection,
  121    SelectionGoal, TextObject, TransactionId, TreeSitterOptions, WordsQuery,
  122    language_settings::{
  123        self, LspInsertMode, RewrapBehavior, WordsCompletionMode, all_language_settings,
  124        language_settings,
  125    },
  126    point_from_lsp, point_to_lsp, text_diff_with_options,
  127};
  128use linked_editing_ranges::refresh_linked_ranges;
  129use lsp::{
  130    CodeActionKind, CompletionItemKind, CompletionTriggerKind, InsertTextFormat, InsertTextMode,
  131    LanguageServerId,
  132};
  133use lsp_colors::LspColorData;
  134use markdown::Markdown;
  135use mouse_context_menu::MouseContextMenu;
  136use movement::TextLayoutDetails;
  137use multi_buffer::{
  138    ExcerptInfo, ExpandExcerptDirection, MultiBufferDiffHunk, MultiBufferPoint, MultiBufferRow,
  139};
  140use parking_lot::Mutex;
  141use persistence::DB;
  142use project::{
  143    BreakpointWithPosition, CodeAction, Completion, CompletionDisplayOptions, CompletionIntent,
  144    CompletionResponse, CompletionSource, DisableAiSettings, DocumentHighlight, InlayHint, InlayId,
  145    InvalidationStrategy, Location, LocationLink, PrepareRenameResponse, Project, ProjectItem,
  146    ProjectPath, ProjectTransaction, TaskSourceKind,
  147    debugger::{
  148        breakpoint_store::{
  149            Breakpoint, BreakpointEditAction, BreakpointSessionState, BreakpointState,
  150            BreakpointStore, BreakpointStoreEvent,
  151        },
  152        session::{Session, SessionEvent},
  153    },
  154    git_store::GitStoreEvent,
  155    lsp_store::{
  156        CacheInlayHints, CompletionDocumentation, FormatTrigger, LspFormatTarget,
  157        OpenLspBufferHandle,
  158    },
  159    project_settings::{DiagnosticSeverity, GoToDiagnosticSeverityFilter, ProjectSettings},
  160};
  161use rand::seq::SliceRandom;
  162use rpc::{ErrorCode, ErrorExt, proto::PeerId};
  163use scroll::{Autoscroll, OngoingScroll, ScrollAnchor, ScrollManager};
  164use selections_collection::{MutableSelectionsCollection, SelectionsCollection};
  165use serde::{Deserialize, Serialize};
  166use settings::{
  167    GitGutterSetting, RelativeLineNumbers, Settings, SettingsLocation, SettingsStore,
  168    update_settings_file,
  169};
  170use smallvec::{SmallVec, smallvec};
  171use snippet::Snippet;
  172use std::{
  173    any::{Any, TypeId},
  174    borrow::Cow,
  175    cell::{OnceCell, RefCell},
  176    cmp::{self, Ordering, Reverse},
  177    iter::{self, Peekable},
  178    mem,
  179    num::NonZeroU32,
  180    ops::{Deref, DerefMut, Not, Range, RangeInclusive},
  181    path::{Path, PathBuf},
  182    rc::Rc,
  183    sync::Arc,
  184    time::{Duration, Instant},
  185};
  186use task::{ResolvedTask, RunnableTag, TaskTemplate, TaskVariables};
  187use text::{BufferId, FromAnchor, OffsetUtf16, Rope, ToOffset as _};
  188use theme::{
  189    ActiveTheme, PlayerColor, StatusColors, SyntaxTheme, Theme, ThemeSettings,
  190    observe_buffer_font_size_adjustment,
  191};
  192use ui::{
  193    ButtonSize, ButtonStyle, ContextMenu, Disclosure, IconButton, IconButtonShape, IconName,
  194    IconSize, Indicator, Key, Tooltip, h_flex, prelude::*, scrollbars::ScrollbarAutoHide,
  195};
  196use util::{RangeExt, ResultExt, TryFutureExt, maybe, post_inc};
  197use workspace::{
  198    CollaboratorId, Item as WorkspaceItem, ItemId, ItemNavHistory, OpenInTerminal, OpenTerminal,
  199    RestoreOnStartupBehavior, SERIALIZATION_THROTTLE_TIME, SplitDirection, TabBarSettings, Toast,
  200    ViewId, Workspace, WorkspaceId, WorkspaceSettings,
  201    item::{ItemBufferKind, ItemHandle, PreviewTabsSettings, SaveOptions},
  202    notifications::{DetachAndPromptErr, NotificationId, NotifyTaskExt},
  203    searchable::SearchEvent,
  204};
  205
  206use crate::{
  207    code_context_menus::CompletionsMenuSource,
  208    editor_settings::MultiCursorModifier,
  209    hover_links::{find_url, find_url_from_range},
  210    inlays::{
  211        InlineValueCache,
  212        inlay_hints::{LspInlayHintData, inlay_hint_settings},
  213    },
  214    scroll::{ScrollOffset, ScrollPixelOffset},
  215    selections_collection::resolve_selections_wrapping_blocks,
  216    signature_help::{SignatureHelpHiddenBy, SignatureHelpState},
  217};
  218
  219pub const FILE_HEADER_HEIGHT: u32 = 2;
  220pub const MULTI_BUFFER_EXCERPT_HEADER_HEIGHT: u32 = 1;
  221const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500);
  222const MAX_LINE_LEN: usize = 1024;
  223const MIN_NAVIGATION_HISTORY_ROW_DELTA: i64 = 10;
  224const MAX_SELECTION_HISTORY_LEN: usize = 1024;
  225pub(crate) const CURSORS_VISIBLE_FOR: Duration = Duration::from_millis(2000);
  226#[doc(hidden)]
  227pub const CODE_ACTIONS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(250);
  228pub const SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(100);
  229
  230pub(crate) const CODE_ACTION_TIMEOUT: Duration = Duration::from_secs(5);
  231pub(crate) const FORMAT_TIMEOUT: Duration = Duration::from_secs(5);
  232pub(crate) const SCROLL_CENTER_TOP_BOTTOM_DEBOUNCE_TIMEOUT: Duration = Duration::from_secs(1);
  233pub const FETCH_COLORS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(150);
  234
  235pub(crate) const EDIT_PREDICTION_KEY_CONTEXT: &str = "edit_prediction";
  236pub(crate) const EDIT_PREDICTION_CONFLICT_KEY_CONTEXT: &str = "edit_prediction_conflict";
  237pub(crate) const MINIMAP_FONT_SIZE: AbsoluteLength = AbsoluteLength::Pixels(px(2.));
  238
  239pub type RenderDiffHunkControlsFn = Arc<
  240    dyn Fn(
  241        u32,
  242        &DiffHunkStatus,
  243        Range<Anchor>,
  244        bool,
  245        Pixels,
  246        &Entity<Editor>,
  247        &mut Window,
  248        &mut App,
  249    ) -> AnyElement,
  250>;
  251
  252enum ReportEditorEvent {
  253    Saved { auto_saved: bool },
  254    EditorOpened,
  255    Closed,
  256}
  257
  258impl ReportEditorEvent {
  259    pub fn event_type(&self) -> &'static str {
  260        match self {
  261            Self::Saved { .. } => "Editor Saved",
  262            Self::EditorOpened => "Editor Opened",
  263            Self::Closed => "Editor Closed",
  264        }
  265    }
  266}
  267
  268pub enum ActiveDebugLine {}
  269pub enum DebugStackFrameLine {}
  270enum DocumentHighlightRead {}
  271enum DocumentHighlightWrite {}
  272enum InputComposition {}
  273pub enum PendingInput {}
  274enum SelectedTextHighlight {}
  275
  276pub enum ConflictsOuter {}
  277pub enum ConflictsOurs {}
  278pub enum ConflictsTheirs {}
  279pub enum ConflictsOursMarker {}
  280pub enum ConflictsTheirsMarker {}
  281
  282#[derive(Debug, Copy, Clone, PartialEq, Eq)]
  283pub enum Navigated {
  284    Yes,
  285    No,
  286}
  287
  288impl Navigated {
  289    pub fn from_bool(yes: bool) -> Navigated {
  290        if yes { Navigated::Yes } else { Navigated::No }
  291    }
  292}
  293
  294#[derive(Debug, Clone, PartialEq, Eq)]
  295enum DisplayDiffHunk {
  296    Folded {
  297        display_row: DisplayRow,
  298    },
  299    Unfolded {
  300        is_created_file: bool,
  301        diff_base_byte_range: Range<usize>,
  302        display_row_range: Range<DisplayRow>,
  303        multi_buffer_range: Range<Anchor>,
  304        status: DiffHunkStatus,
  305    },
  306}
  307
  308pub enum HideMouseCursorOrigin {
  309    TypingAction,
  310    MovementAction,
  311}
  312
  313pub fn init(cx: &mut App) {
  314    cx.set_global(GlobalBlameRenderer(Arc::new(())));
  315
  316    workspace::register_project_item::<Editor>(cx);
  317    workspace::FollowableViewRegistry::register::<Editor>(cx);
  318    workspace::register_serializable_item::<Editor>(cx);
  319
  320    cx.observe_new(
  321        |workspace: &mut Workspace, _: Option<&mut Window>, _cx: &mut Context<Workspace>| {
  322            workspace.register_action(Editor::new_file);
  323            workspace.register_action(Editor::new_file_split);
  324            workspace.register_action(Editor::new_file_vertical);
  325            workspace.register_action(Editor::new_file_horizontal);
  326            workspace.register_action(Editor::cancel_language_server_work);
  327            workspace.register_action(Editor::toggle_focus);
  328        },
  329    )
  330    .detach();
  331
  332    cx.on_action(move |_: &workspace::NewFile, cx| {
  333        let app_state = workspace::AppState::global(cx);
  334        if let Some(app_state) = app_state.upgrade() {
  335            workspace::open_new(
  336                Default::default(),
  337                app_state,
  338                cx,
  339                |workspace, window, cx| {
  340                    Editor::new_file(workspace, &Default::default(), window, cx)
  341                },
  342            )
  343            .detach();
  344        }
  345    });
  346    cx.on_action(move |_: &workspace::NewWindow, cx| {
  347        let app_state = workspace::AppState::global(cx);
  348        if let Some(app_state) = app_state.upgrade() {
  349            workspace::open_new(
  350                Default::default(),
  351                app_state,
  352                cx,
  353                |workspace, window, cx| {
  354                    cx.activate(true);
  355                    Editor::new_file(workspace, &Default::default(), window, cx)
  356                },
  357            )
  358            .detach();
  359        }
  360    });
  361}
  362
  363pub fn set_blame_renderer(renderer: impl BlameRenderer + 'static, cx: &mut App) {
  364    cx.set_global(GlobalBlameRenderer(Arc::new(renderer)));
  365}
  366
  367pub trait DiagnosticRenderer {
  368    fn render_group(
  369        &self,
  370        diagnostic_group: Vec<DiagnosticEntryRef<'_, Point>>,
  371        buffer_id: BufferId,
  372        snapshot: EditorSnapshot,
  373        editor: WeakEntity<Editor>,
  374        cx: &mut App,
  375    ) -> Vec<BlockProperties<Anchor>>;
  376
  377    fn render_hover(
  378        &self,
  379        diagnostic_group: Vec<DiagnosticEntryRef<'_, Point>>,
  380        range: Range<Point>,
  381        buffer_id: BufferId,
  382        cx: &mut App,
  383    ) -> Option<Entity<markdown::Markdown>>;
  384
  385    fn open_link(
  386        &self,
  387        editor: &mut Editor,
  388        link: SharedString,
  389        window: &mut Window,
  390        cx: &mut Context<Editor>,
  391    );
  392}
  393
  394pub(crate) struct GlobalDiagnosticRenderer(pub Arc<dyn DiagnosticRenderer>);
  395
  396impl GlobalDiagnosticRenderer {
  397    fn global(cx: &App) -> Option<Arc<dyn DiagnosticRenderer>> {
  398        cx.try_global::<Self>().map(|g| g.0.clone())
  399    }
  400}
  401
  402impl gpui::Global for GlobalDiagnosticRenderer {}
  403pub fn set_diagnostic_renderer(renderer: impl DiagnosticRenderer + 'static, cx: &mut App) {
  404    cx.set_global(GlobalDiagnosticRenderer(Arc::new(renderer)));
  405}
  406
  407pub struct SearchWithinRange;
  408
  409trait InvalidationRegion {
  410    fn ranges(&self) -> &[Range<Anchor>];
  411}
  412
  413#[derive(Clone, Debug, PartialEq)]
  414pub enum SelectPhase {
  415    Begin {
  416        position: DisplayPoint,
  417        add: bool,
  418        click_count: usize,
  419    },
  420    BeginColumnar {
  421        position: DisplayPoint,
  422        reset: bool,
  423        mode: ColumnarMode,
  424        goal_column: u32,
  425    },
  426    Extend {
  427        position: DisplayPoint,
  428        click_count: usize,
  429    },
  430    Update {
  431        position: DisplayPoint,
  432        goal_column: u32,
  433        scroll_delta: gpui::Point<f32>,
  434    },
  435    End,
  436}
  437
  438#[derive(Clone, Debug, PartialEq)]
  439pub enum ColumnarMode {
  440    FromMouse,
  441    FromSelection,
  442}
  443
  444#[derive(Clone, Debug)]
  445pub enum SelectMode {
  446    Character,
  447    Word(Range<Anchor>),
  448    Line(Range<Anchor>),
  449    All,
  450}
  451
  452#[derive(Copy, Clone, Default, PartialEq, Eq, Debug)]
  453pub enum SizingBehavior {
  454    /// The editor will layout itself using `size_full` and will include the vertical
  455    /// scroll margin as requested by user settings.
  456    #[default]
  457    Default,
  458    /// The editor will layout itself using `size_full`, but will not have any
  459    /// vertical overscroll.
  460    ExcludeOverscrollMargin,
  461    /// The editor will request a vertical size according to its content and will be
  462    /// layouted without a vertical scroll margin.
  463    SizeByContent,
  464}
  465
  466#[derive(Clone, PartialEq, Eq, Debug)]
  467pub enum EditorMode {
  468    SingleLine,
  469    AutoHeight {
  470        min_lines: usize,
  471        max_lines: Option<usize>,
  472    },
  473    Full {
  474        /// When set to `true`, the editor will scale its UI elements with the buffer font size.
  475        scale_ui_elements_with_buffer_font_size: bool,
  476        /// When set to `true`, the editor will render a background for the active line.
  477        show_active_line_background: bool,
  478        /// Determines the sizing behavior for this editor
  479        sizing_behavior: SizingBehavior,
  480    },
  481    Minimap {
  482        parent: WeakEntity<Editor>,
  483    },
  484}
  485
  486impl EditorMode {
  487    pub fn full() -> Self {
  488        Self::Full {
  489            scale_ui_elements_with_buffer_font_size: true,
  490            show_active_line_background: true,
  491            sizing_behavior: SizingBehavior::Default,
  492        }
  493    }
  494
  495    #[inline]
  496    pub fn is_full(&self) -> bool {
  497        matches!(self, Self::Full { .. })
  498    }
  499
  500    #[inline]
  501    pub fn is_single_line(&self) -> bool {
  502        matches!(self, Self::SingleLine { .. })
  503    }
  504
  505    #[inline]
  506    fn is_minimap(&self) -> bool {
  507        matches!(self, Self::Minimap { .. })
  508    }
  509}
  510
  511#[derive(Copy, Clone, Debug)]
  512pub enum SoftWrap {
  513    /// Prefer not to wrap at all.
  514    ///
  515    /// Note: this is currently internal, as actually limited by [`crate::MAX_LINE_LEN`] until it wraps.
  516    /// The mode is used inside git diff hunks, where it's seems currently more useful to not wrap as much as possible.
  517    GitDiff,
  518    /// Prefer a single line generally, unless an overly long line is encountered.
  519    None,
  520    /// Soft wrap lines that exceed the editor width.
  521    EditorWidth,
  522    /// Soft wrap lines at the preferred line length.
  523    Column(u32),
  524    /// Soft wrap line at the preferred line length or the editor width (whichever is smaller).
  525    Bounded(u32),
  526}
  527
  528#[derive(Clone)]
  529pub struct EditorStyle {
  530    pub background: Hsla,
  531    pub border: Hsla,
  532    pub local_player: PlayerColor,
  533    pub text: TextStyle,
  534    pub scrollbar_width: Pixels,
  535    pub syntax: Arc<SyntaxTheme>,
  536    pub status: StatusColors,
  537    pub inlay_hints_style: HighlightStyle,
  538    pub edit_prediction_styles: EditPredictionStyles,
  539    pub unnecessary_code_fade: f32,
  540    pub show_underlines: bool,
  541}
  542
  543impl Default for EditorStyle {
  544    fn default() -> Self {
  545        Self {
  546            background: Hsla::default(),
  547            border: Hsla::default(),
  548            local_player: PlayerColor::default(),
  549            text: TextStyle::default(),
  550            scrollbar_width: Pixels::default(),
  551            syntax: Default::default(),
  552            // HACK: Status colors don't have a real default.
  553            // We should look into removing the status colors from the editor
  554            // style and retrieve them directly from the theme.
  555            status: StatusColors::dark(),
  556            inlay_hints_style: HighlightStyle::default(),
  557            edit_prediction_styles: EditPredictionStyles {
  558                insertion: HighlightStyle::default(),
  559                whitespace: HighlightStyle::default(),
  560            },
  561            unnecessary_code_fade: Default::default(),
  562            show_underlines: true,
  563        }
  564    }
  565}
  566
  567pub fn make_inlay_hints_style(cx: &mut App) -> HighlightStyle {
  568    let show_background = language_settings::language_settings(None, None, cx)
  569        .inlay_hints
  570        .show_background;
  571
  572    let mut style = cx.theme().syntax().get("hint");
  573
  574    if style.color.is_none() {
  575        style.color = Some(cx.theme().status().hint);
  576    }
  577
  578    if !show_background {
  579        style.background_color = None;
  580        return style;
  581    }
  582
  583    if style.background_color.is_none() {
  584        style.background_color = Some(cx.theme().status().hint_background);
  585    }
  586
  587    style
  588}
  589
  590pub fn make_suggestion_styles(cx: &mut App) -> EditPredictionStyles {
  591    EditPredictionStyles {
  592        insertion: HighlightStyle {
  593            color: Some(cx.theme().status().predictive),
  594            ..HighlightStyle::default()
  595        },
  596        whitespace: HighlightStyle {
  597            background_color: Some(cx.theme().status().created_background),
  598            ..HighlightStyle::default()
  599        },
  600    }
  601}
  602
  603type CompletionId = usize;
  604
  605pub(crate) enum EditDisplayMode {
  606    TabAccept,
  607    DiffPopover,
  608    Inline,
  609}
  610
  611enum EditPrediction {
  612    Edit {
  613        edits: Vec<(Range<Anchor>, Arc<str>)>,
  614        edit_preview: Option<EditPreview>,
  615        display_mode: EditDisplayMode,
  616        snapshot: BufferSnapshot,
  617    },
  618    /// Move to a specific location in the active editor
  619    MoveWithin {
  620        target: Anchor,
  621        snapshot: BufferSnapshot,
  622    },
  623    /// Move to a specific location in a different editor (not the active one)
  624    MoveOutside {
  625        target: language::Anchor,
  626        snapshot: BufferSnapshot,
  627    },
  628}
  629
  630struct EditPredictionState {
  631    inlay_ids: Vec<InlayId>,
  632    completion: EditPrediction,
  633    completion_id: Option<SharedString>,
  634    invalidation_range: Option<Range<Anchor>>,
  635}
  636
  637enum EditPredictionSettings {
  638    Disabled,
  639    Enabled {
  640        show_in_menu: bool,
  641        preview_requires_modifier: bool,
  642    },
  643}
  644
  645enum EditPredictionHighlight {}
  646
  647#[derive(Debug, Clone)]
  648struct InlineDiagnostic {
  649    message: SharedString,
  650    group_id: usize,
  651    is_primary: bool,
  652    start: Point,
  653    severity: lsp::DiagnosticSeverity,
  654}
  655
  656pub enum MenuEditPredictionsPolicy {
  657    Never,
  658    ByProvider,
  659}
  660
  661pub enum EditPredictionPreview {
  662    /// Modifier is not pressed
  663    Inactive { released_too_fast: bool },
  664    /// Modifier pressed
  665    Active {
  666        since: Instant,
  667        previous_scroll_position: Option<ScrollAnchor>,
  668    },
  669}
  670
  671impl EditPredictionPreview {
  672    pub fn released_too_fast(&self) -> bool {
  673        match self {
  674            EditPredictionPreview::Inactive { released_too_fast } => *released_too_fast,
  675            EditPredictionPreview::Active { .. } => false,
  676        }
  677    }
  678
  679    pub fn set_previous_scroll_position(&mut self, scroll_position: Option<ScrollAnchor>) {
  680        if let EditPredictionPreview::Active {
  681            previous_scroll_position,
  682            ..
  683        } = self
  684        {
  685            *previous_scroll_position = scroll_position;
  686        }
  687    }
  688}
  689
  690pub struct ContextMenuOptions {
  691    pub min_entries_visible: usize,
  692    pub max_entries_visible: usize,
  693    pub placement: Option<ContextMenuPlacement>,
  694}
  695
  696#[derive(Debug, Clone, PartialEq, Eq)]
  697pub enum ContextMenuPlacement {
  698    Above,
  699    Below,
  700}
  701
  702#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug, Default)]
  703struct EditorActionId(usize);
  704
  705impl EditorActionId {
  706    pub fn post_inc(&mut self) -> Self {
  707        let answer = self.0;
  708
  709        *self = Self(answer + 1);
  710
  711        Self(answer)
  712    }
  713}
  714
  715// type GetFieldEditorTheme = dyn Fn(&theme::Theme) -> theme::FieldEditor;
  716// type OverrideTextStyle = dyn Fn(&EditorStyle) -> Option<HighlightStyle>;
  717
  718type BackgroundHighlight = (fn(&Theme) -> Hsla, Arc<[Range<Anchor>]>);
  719type GutterHighlight = (fn(&App) -> Hsla, Vec<Range<Anchor>>);
  720
  721#[derive(Default)]
  722struct ScrollbarMarkerState {
  723    scrollbar_size: Size<Pixels>,
  724    dirty: bool,
  725    markers: Arc<[PaintQuad]>,
  726    pending_refresh: Option<Task<Result<()>>>,
  727}
  728
  729impl ScrollbarMarkerState {
  730    fn should_refresh(&self, scrollbar_size: Size<Pixels>) -> bool {
  731        self.pending_refresh.is_none() && (self.scrollbar_size != scrollbar_size || self.dirty)
  732    }
  733}
  734
  735#[derive(Clone, Copy, PartialEq, Eq)]
  736pub enum MinimapVisibility {
  737    Disabled,
  738    Enabled {
  739        /// The configuration currently present in the users settings.
  740        setting_configuration: bool,
  741        /// Whether to override the currently set visibility from the users setting.
  742        toggle_override: bool,
  743    },
  744}
  745
  746impl MinimapVisibility {
  747    fn for_mode(mode: &EditorMode, cx: &App) -> Self {
  748        if mode.is_full() {
  749            Self::Enabled {
  750                setting_configuration: EditorSettings::get_global(cx).minimap.minimap_enabled(),
  751                toggle_override: false,
  752            }
  753        } else {
  754            Self::Disabled
  755        }
  756    }
  757
  758    fn hidden(&self) -> Self {
  759        match *self {
  760            Self::Enabled {
  761                setting_configuration,
  762                ..
  763            } => Self::Enabled {
  764                setting_configuration,
  765                toggle_override: setting_configuration,
  766            },
  767            Self::Disabled => Self::Disabled,
  768        }
  769    }
  770
  771    fn disabled(&self) -> bool {
  772        matches!(*self, Self::Disabled)
  773    }
  774
  775    fn settings_visibility(&self) -> bool {
  776        match *self {
  777            Self::Enabled {
  778                setting_configuration,
  779                ..
  780            } => setting_configuration,
  781            _ => false,
  782        }
  783    }
  784
  785    fn visible(&self) -> bool {
  786        match *self {
  787            Self::Enabled {
  788                setting_configuration,
  789                toggle_override,
  790            } => setting_configuration ^ toggle_override,
  791            _ => false,
  792        }
  793    }
  794
  795    fn toggle_visibility(&self) -> Self {
  796        match *self {
  797            Self::Enabled {
  798                toggle_override,
  799                setting_configuration,
  800            } => Self::Enabled {
  801                setting_configuration,
  802                toggle_override: !toggle_override,
  803            },
  804            Self::Disabled => Self::Disabled,
  805        }
  806    }
  807}
  808
  809#[derive(Debug, Clone, Copy, PartialEq, Eq)]
  810pub enum BufferSerialization {
  811    All,
  812    NonDirtyBuffers,
  813}
  814
  815impl BufferSerialization {
  816    fn new(restore_unsaved_buffers: bool) -> Self {
  817        if restore_unsaved_buffers {
  818            Self::All
  819        } else {
  820            Self::NonDirtyBuffers
  821        }
  822    }
  823}
  824
  825#[derive(Clone, Debug)]
  826struct RunnableTasks {
  827    templates: Vec<(TaskSourceKind, TaskTemplate)>,
  828    offset: multi_buffer::Anchor,
  829    // We need the column at which the task context evaluation should take place (when we're spawning it via gutter).
  830    column: u32,
  831    // Values of all named captures, including those starting with '_'
  832    extra_variables: HashMap<String, String>,
  833    // Full range of the tagged region. We use it to determine which `extra_variables` to grab for context resolution in e.g. a modal.
  834    context_range: Range<BufferOffset>,
  835}
  836
  837impl RunnableTasks {
  838    fn resolve<'a>(
  839        &'a self,
  840        cx: &'a task::TaskContext,
  841    ) -> impl Iterator<Item = (TaskSourceKind, ResolvedTask)> + 'a {
  842        self.templates.iter().filter_map(|(kind, template)| {
  843            template
  844                .resolve_task(&kind.to_id_base(), cx)
  845                .map(|task| (kind.clone(), task))
  846        })
  847    }
  848}
  849
  850#[derive(Clone)]
  851pub struct ResolvedTasks {
  852    templates: SmallVec<[(TaskSourceKind, ResolvedTask); 1]>,
  853    position: Anchor,
  854}
  855
  856#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
  857struct BufferOffset(usize);
  858
  859/// Addons allow storing per-editor state in other crates (e.g. Vim)
  860pub trait Addon: 'static {
  861    fn extend_key_context(&self, _: &mut KeyContext, _: &App) {}
  862
  863    fn render_buffer_header_controls(
  864        &self,
  865        _: &ExcerptInfo,
  866        _: &Window,
  867        _: &App,
  868    ) -> Option<AnyElement> {
  869        None
  870    }
  871
  872    fn override_status_for_buffer_id(&self, _: BufferId, _: &App) -> Option<FileStatus> {
  873        None
  874    }
  875
  876    fn to_any(&self) -> &dyn std::any::Any;
  877
  878    fn to_any_mut(&mut self) -> Option<&mut dyn std::any::Any> {
  879        None
  880    }
  881}
  882
  883struct ChangeLocation {
  884    current: Option<Vec<Anchor>>,
  885    original: Vec<Anchor>,
  886}
  887impl ChangeLocation {
  888    fn locations(&self) -> &[Anchor] {
  889        self.current.as_ref().unwrap_or(&self.original)
  890    }
  891}
  892
  893/// A set of caret positions, registered when the editor was edited.
  894pub struct ChangeList {
  895    changes: Vec<ChangeLocation>,
  896    /// Currently "selected" change.
  897    position: Option<usize>,
  898}
  899
  900impl ChangeList {
  901    pub fn new() -> Self {
  902        Self {
  903            changes: Vec::new(),
  904            position: None,
  905        }
  906    }
  907
  908    /// Moves to the next change in the list (based on the direction given) and returns the caret positions for the next change.
  909    /// If reaches the end of the list in the direction, returns the corresponding change until called for a different direction.
  910    pub fn next_change(&mut self, count: usize, direction: Direction) -> Option<&[Anchor]> {
  911        if self.changes.is_empty() {
  912            return None;
  913        }
  914
  915        let prev = self.position.unwrap_or(self.changes.len());
  916        let next = if direction == Direction::Prev {
  917            prev.saturating_sub(count)
  918        } else {
  919            (prev + count).min(self.changes.len() - 1)
  920        };
  921        self.position = Some(next);
  922        self.changes.get(next).map(|change| change.locations())
  923    }
  924
  925    /// Adds a new change to the list, resetting the change list position.
  926    pub fn push_to_change_list(&mut self, group: bool, new_positions: Vec<Anchor>) {
  927        self.position.take();
  928        if let Some(last) = self.changes.last_mut()
  929            && group
  930        {
  931            last.current = Some(new_positions)
  932        } else {
  933            self.changes.push(ChangeLocation {
  934                original: new_positions,
  935                current: None,
  936            });
  937        }
  938    }
  939
  940    pub fn last(&self) -> Option<&[Anchor]> {
  941        self.changes.last().map(|change| change.locations())
  942    }
  943
  944    pub fn last_before_grouping(&self) -> Option<&[Anchor]> {
  945        self.changes.last().map(|change| change.original.as_slice())
  946    }
  947
  948    pub fn invert_last_group(&mut self) {
  949        if let Some(last) = self.changes.last_mut()
  950            && let Some(current) = last.current.as_mut()
  951        {
  952            mem::swap(&mut last.original, current);
  953        }
  954    }
  955}
  956
  957#[derive(Clone)]
  958struct InlineBlamePopoverState {
  959    scroll_handle: ScrollHandle,
  960    commit_message: Option<ParsedCommitMessage>,
  961    markdown: Entity<Markdown>,
  962}
  963
  964struct InlineBlamePopover {
  965    position: gpui::Point<Pixels>,
  966    hide_task: Option<Task<()>>,
  967    popover_bounds: Option<Bounds<Pixels>>,
  968    popover_state: InlineBlamePopoverState,
  969    keyboard_grace: bool,
  970}
  971
  972enum SelectionDragState {
  973    /// State when no drag related activity is detected.
  974    None,
  975    /// State when the mouse is down on a selection that is about to be dragged.
  976    ReadyToDrag {
  977        selection: Selection<Anchor>,
  978        click_position: gpui::Point<Pixels>,
  979        mouse_down_time: Instant,
  980    },
  981    /// State when the mouse is dragging the selection in the editor.
  982    Dragging {
  983        selection: Selection<Anchor>,
  984        drop_cursor: Selection<Anchor>,
  985        hide_drop_cursor: bool,
  986    },
  987}
  988
  989enum ColumnarSelectionState {
  990    FromMouse {
  991        selection_tail: Anchor,
  992        display_point: Option<DisplayPoint>,
  993    },
  994    FromSelection {
  995        selection_tail: Anchor,
  996    },
  997}
  998
  999/// Represents a breakpoint indicator that shows up when hovering over lines in the gutter that don't have
 1000/// a breakpoint on them.
 1001#[derive(Clone, Copy, Debug, PartialEq, Eq)]
 1002struct PhantomBreakpointIndicator {
 1003    display_row: DisplayRow,
 1004    /// There's a small debounce between hovering over the line and showing the indicator.
 1005    /// We don't want to show the indicator when moving the mouse from editor to e.g. project panel.
 1006    is_active: bool,
 1007    collides_with_existing_breakpoint: bool,
 1008}
 1009
 1010/// Zed's primary implementation of text input, allowing users to edit a [`MultiBuffer`].
 1011///
 1012/// See the [module level documentation](self) for more information.
 1013pub struct Editor {
 1014    focus_handle: FocusHandle,
 1015    last_focused_descendant: Option<WeakFocusHandle>,
 1016    /// The text buffer being edited
 1017    buffer: Entity<MultiBuffer>,
 1018    /// Map of how text in the buffer should be displayed.
 1019    /// Handles soft wraps, folds, fake inlay text insertions, etc.
 1020    pub display_map: Entity<DisplayMap>,
 1021    placeholder_display_map: Option<Entity<DisplayMap>>,
 1022    pub selections: SelectionsCollection,
 1023    pub scroll_manager: ScrollManager,
 1024    /// When inline assist editors are linked, they all render cursors because
 1025    /// typing enters text into each of them, even the ones that aren't focused.
 1026    pub(crate) show_cursor_when_unfocused: bool,
 1027    columnar_selection_state: Option<ColumnarSelectionState>,
 1028    add_selections_state: Option<AddSelectionsState>,
 1029    select_next_state: Option<SelectNextState>,
 1030    select_prev_state: Option<SelectNextState>,
 1031    selection_history: SelectionHistory,
 1032    defer_selection_effects: bool,
 1033    deferred_selection_effects_state: Option<DeferredSelectionEffectsState>,
 1034    autoclose_regions: Vec<AutocloseRegion>,
 1035    snippet_stack: InvalidationStack<SnippetState>,
 1036    select_syntax_node_history: SelectSyntaxNodeHistory,
 1037    ime_transaction: Option<TransactionId>,
 1038    pub diagnostics_max_severity: DiagnosticSeverity,
 1039    active_diagnostics: ActiveDiagnostic,
 1040    show_inline_diagnostics: bool,
 1041    inline_diagnostics_update: Task<()>,
 1042    inline_diagnostics_enabled: bool,
 1043    diagnostics_enabled: bool,
 1044    word_completions_enabled: bool,
 1045    inline_diagnostics: Vec<(Anchor, InlineDiagnostic)>,
 1046    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
 1047    hard_wrap: Option<usize>,
 1048    project: Option<Entity<Project>>,
 1049    semantics_provider: Option<Rc<dyn SemanticsProvider>>,
 1050    completion_provider: Option<Rc<dyn CompletionProvider>>,
 1051    collaboration_hub: Option<Box<dyn CollaborationHub>>,
 1052    blink_manager: Entity<BlinkManager>,
 1053    show_cursor_names: bool,
 1054    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
 1055    pub show_local_selections: bool,
 1056    mode: EditorMode,
 1057    show_breadcrumbs: bool,
 1058    show_gutter: bool,
 1059    show_scrollbars: ScrollbarAxes,
 1060    minimap_visibility: MinimapVisibility,
 1061    offset_content: bool,
 1062    disable_expand_excerpt_buttons: bool,
 1063    show_line_numbers: Option<bool>,
 1064    use_relative_line_numbers: Option<bool>,
 1065    show_git_diff_gutter: Option<bool>,
 1066    show_code_actions: Option<bool>,
 1067    show_runnables: Option<bool>,
 1068    show_breakpoints: Option<bool>,
 1069    show_wrap_guides: Option<bool>,
 1070    show_indent_guides: Option<bool>,
 1071    highlight_order: usize,
 1072    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
 1073    background_highlights: HashMap<HighlightKey, BackgroundHighlight>,
 1074    gutter_highlights: HashMap<TypeId, GutterHighlight>,
 1075    scrollbar_marker_state: ScrollbarMarkerState,
 1076    active_indent_guides_state: ActiveIndentGuidesState,
 1077    nav_history: Option<ItemNavHistory>,
 1078    context_menu: RefCell<Option<CodeContextMenu>>,
 1079    context_menu_options: Option<ContextMenuOptions>,
 1080    mouse_context_menu: Option<MouseContextMenu>,
 1081    completion_tasks: Vec<(CompletionId, Task<()>)>,
 1082    inline_blame_popover: Option<InlineBlamePopover>,
 1083    inline_blame_popover_show_task: Option<Task<()>>,
 1084    signature_help_state: SignatureHelpState,
 1085    auto_signature_help: Option<bool>,
 1086    find_all_references_task_sources: Vec<Anchor>,
 1087    next_completion_id: CompletionId,
 1088    available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
 1089    code_actions_task: Option<Task<Result<()>>>,
 1090    quick_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1091    debounced_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1092    document_highlights_task: Option<Task<()>>,
 1093    linked_editing_range_task: Option<Task<Option<()>>>,
 1094    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
 1095    pending_rename: Option<RenameState>,
 1096    searchable: bool,
 1097    cursor_shape: CursorShape,
 1098    current_line_highlight: Option<CurrentLineHighlight>,
 1099    autoindent_mode: Option<AutoindentMode>,
 1100    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
 1101    input_enabled: bool,
 1102    use_modal_editing: bool,
 1103    read_only: bool,
 1104    leader_id: Option<CollaboratorId>,
 1105    remote_id: Option<ViewId>,
 1106    pub hover_state: HoverState,
 1107    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
 1108    gutter_hovered: bool,
 1109    hovered_link_state: Option<HoveredLinkState>,
 1110    edit_prediction_provider: Option<RegisteredEditPredictionProvider>,
 1111    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
 1112    active_edit_prediction: Option<EditPredictionState>,
 1113    /// Used to prevent flickering as the user types while the menu is open
 1114    stale_edit_prediction_in_menu: Option<EditPredictionState>,
 1115    edit_prediction_settings: EditPredictionSettings,
 1116    edit_predictions_hidden_for_vim_mode: bool,
 1117    show_edit_predictions_override: Option<bool>,
 1118    menu_edit_predictions_policy: MenuEditPredictionsPolicy,
 1119    edit_prediction_preview: EditPredictionPreview,
 1120    edit_prediction_indent_conflict: bool,
 1121    edit_prediction_requires_modifier_in_indent_conflict: bool,
 1122    next_inlay_id: usize,
 1123    next_color_inlay_id: usize,
 1124    _subscriptions: Vec<Subscription>,
 1125    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
 1126    gutter_dimensions: GutterDimensions,
 1127    style: Option<EditorStyle>,
 1128    text_style_refinement: Option<TextStyleRefinement>,
 1129    next_editor_action_id: EditorActionId,
 1130    editor_actions: Rc<
 1131        RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&Editor, &mut Window, &mut Context<Self>)>>>,
 1132    >,
 1133    use_autoclose: bool,
 1134    use_auto_surround: bool,
 1135    auto_replace_emoji_shortcode: bool,
 1136    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1137    show_git_blame_gutter: bool,
 1138    show_git_blame_inline: bool,
 1139    show_git_blame_inline_delay_task: Option<Task<()>>,
 1140    git_blame_inline_enabled: bool,
 1141    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1142    buffer_serialization: Option<BufferSerialization>,
 1143    show_selection_menu: Option<bool>,
 1144    blame: Option<Entity<GitBlame>>,
 1145    blame_subscription: Option<Subscription>,
 1146    custom_context_menu: Option<
 1147        Box<
 1148            dyn 'static
 1149                + Fn(
 1150                    &mut Self,
 1151                    DisplayPoint,
 1152                    &mut Window,
 1153                    &mut Context<Self>,
 1154                ) -> Option<Entity<ui::ContextMenu>>,
 1155        >,
 1156    >,
 1157    last_bounds: Option<Bounds<Pixels>>,
 1158    last_position_map: Option<Rc<PositionMap>>,
 1159    expect_bounds_change: Option<Bounds<Pixels>>,
 1160    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
 1161    tasks_update_task: Option<Task<()>>,
 1162    breakpoint_store: Option<Entity<BreakpointStore>>,
 1163    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1164    hovered_diff_hunk_row: Option<DisplayRow>,
 1165    pull_diagnostics_task: Task<()>,
 1166    in_project_search: bool,
 1167    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1168    breadcrumb_header: Option<String>,
 1169    focused_block: Option<FocusedBlock>,
 1170    next_scroll_position: NextScrollCursorCenterTopBottom,
 1171    addons: HashMap<TypeId, Box<dyn Addon>>,
 1172    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1173    load_diff_task: Option<Shared<Task<()>>>,
 1174    /// Whether we are temporarily displaying a diff other than git's
 1175    temporary_diff_override: bool,
 1176    selection_mark_mode: bool,
 1177    toggle_fold_multiple_buffers: Task<()>,
 1178    _scroll_cursor_center_top_bottom_task: Task<()>,
 1179    serialize_selections: Task<()>,
 1180    serialize_folds: Task<()>,
 1181    mouse_cursor_hidden: bool,
 1182    minimap: Option<Entity<Self>>,
 1183    hide_mouse_mode: HideMouseMode,
 1184    pub change_list: ChangeList,
 1185    inline_value_cache: InlineValueCache,
 1186
 1187    selection_drag_state: SelectionDragState,
 1188    colors: Option<LspColorData>,
 1189    post_scroll_update: Task<()>,
 1190    refresh_colors_task: Task<()>,
 1191    inlay_hints: Option<LspInlayHintData>,
 1192    folding_newlines: Task<()>,
 1193    pub lookup_key: Option<Box<dyn Any + Send + Sync>>,
 1194}
 1195
 1196fn debounce_value(debounce_ms: u64) -> Option<Duration> {
 1197    if debounce_ms > 0 {
 1198        Some(Duration::from_millis(debounce_ms))
 1199    } else {
 1200        None
 1201    }
 1202}
 1203
 1204#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1205enum NextScrollCursorCenterTopBottom {
 1206    #[default]
 1207    Center,
 1208    Top,
 1209    Bottom,
 1210}
 1211
 1212impl NextScrollCursorCenterTopBottom {
 1213    fn next(&self) -> Self {
 1214        match self {
 1215            Self::Center => Self::Top,
 1216            Self::Top => Self::Bottom,
 1217            Self::Bottom => Self::Center,
 1218        }
 1219    }
 1220}
 1221
 1222#[derive(Clone)]
 1223pub struct EditorSnapshot {
 1224    pub mode: EditorMode,
 1225    show_gutter: bool,
 1226    show_line_numbers: Option<bool>,
 1227    show_git_diff_gutter: Option<bool>,
 1228    show_code_actions: Option<bool>,
 1229    show_runnables: Option<bool>,
 1230    show_breakpoints: Option<bool>,
 1231    git_blame_gutter_max_author_length: Option<usize>,
 1232    pub display_snapshot: DisplaySnapshot,
 1233    pub placeholder_display_snapshot: Option<DisplaySnapshot>,
 1234    is_focused: bool,
 1235    scroll_anchor: ScrollAnchor,
 1236    ongoing_scroll: OngoingScroll,
 1237    current_line_highlight: CurrentLineHighlight,
 1238    gutter_hovered: bool,
 1239}
 1240
 1241#[derive(Default, Debug, Clone, Copy)]
 1242pub struct GutterDimensions {
 1243    pub left_padding: Pixels,
 1244    pub right_padding: Pixels,
 1245    pub width: Pixels,
 1246    pub margin: Pixels,
 1247    pub git_blame_entries_width: Option<Pixels>,
 1248}
 1249
 1250impl GutterDimensions {
 1251    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1252        Self {
 1253            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1254            ..Default::default()
 1255        }
 1256    }
 1257
 1258    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1259        -cx.text_system().descent(font_id, font_size)
 1260    }
 1261    /// The full width of the space taken up by the gutter.
 1262    pub fn full_width(&self) -> Pixels {
 1263        self.margin + self.width
 1264    }
 1265
 1266    /// The width of the space reserved for the fold indicators,
 1267    /// use alongside 'justify_end' and `gutter_width` to
 1268    /// right align content with the line numbers
 1269    pub fn fold_area_width(&self) -> Pixels {
 1270        self.margin + self.right_padding
 1271    }
 1272}
 1273
 1274struct CharacterDimensions {
 1275    em_width: Pixels,
 1276    em_advance: Pixels,
 1277    line_height: Pixels,
 1278}
 1279
 1280#[derive(Debug)]
 1281pub struct RemoteSelection {
 1282    pub replica_id: ReplicaId,
 1283    pub selection: Selection<Anchor>,
 1284    pub cursor_shape: CursorShape,
 1285    pub collaborator_id: CollaboratorId,
 1286    pub line_mode: bool,
 1287    pub user_name: Option<SharedString>,
 1288    pub color: PlayerColor,
 1289}
 1290
 1291#[derive(Clone, Debug)]
 1292struct SelectionHistoryEntry {
 1293    selections: Arc<[Selection<Anchor>]>,
 1294    select_next_state: Option<SelectNextState>,
 1295    select_prev_state: Option<SelectNextState>,
 1296    add_selections_state: Option<AddSelectionsState>,
 1297}
 1298
 1299#[derive(Copy, Clone, Debug, PartialEq, Eq)]
 1300enum SelectionHistoryMode {
 1301    Normal,
 1302    Undoing,
 1303    Redoing,
 1304    Skipping,
 1305}
 1306
 1307#[derive(Clone, PartialEq, Eq, Hash)]
 1308struct HoveredCursor {
 1309    replica_id: ReplicaId,
 1310    selection_id: usize,
 1311}
 1312
 1313impl Default for SelectionHistoryMode {
 1314    fn default() -> Self {
 1315        Self::Normal
 1316    }
 1317}
 1318
 1319#[derive(Debug)]
 1320/// SelectionEffects controls the side-effects of updating the selection.
 1321///
 1322/// The default behaviour does "what you mostly want":
 1323/// - it pushes to the nav history if the cursor moved by >10 lines
 1324/// - it re-triggers completion requests
 1325/// - it scrolls to fit
 1326///
 1327/// You might want to modify these behaviours. For example when doing a "jump"
 1328/// like go to definition, we always want to add to nav history; but when scrolling
 1329/// in vim mode we never do.
 1330///
 1331/// Similarly, you might want to disable scrolling if you don't want the viewport to
 1332/// move.
 1333#[derive(Clone)]
 1334pub struct SelectionEffects {
 1335    nav_history: Option<bool>,
 1336    completions: bool,
 1337    scroll: Option<Autoscroll>,
 1338}
 1339
 1340impl Default for SelectionEffects {
 1341    fn default() -> Self {
 1342        Self {
 1343            nav_history: None,
 1344            completions: true,
 1345            scroll: Some(Autoscroll::fit()),
 1346        }
 1347    }
 1348}
 1349impl SelectionEffects {
 1350    pub fn scroll(scroll: Autoscroll) -> Self {
 1351        Self {
 1352            scroll: Some(scroll),
 1353            ..Default::default()
 1354        }
 1355    }
 1356
 1357    pub fn no_scroll() -> Self {
 1358        Self {
 1359            scroll: None,
 1360            ..Default::default()
 1361        }
 1362    }
 1363
 1364    pub fn completions(self, completions: bool) -> Self {
 1365        Self {
 1366            completions,
 1367            ..self
 1368        }
 1369    }
 1370
 1371    pub fn nav_history(self, nav_history: bool) -> Self {
 1372        Self {
 1373            nav_history: Some(nav_history),
 1374            ..self
 1375        }
 1376    }
 1377}
 1378
 1379struct DeferredSelectionEffectsState {
 1380    changed: bool,
 1381    effects: SelectionEffects,
 1382    old_cursor_position: Anchor,
 1383    history_entry: SelectionHistoryEntry,
 1384}
 1385
 1386#[derive(Default)]
 1387struct SelectionHistory {
 1388    #[allow(clippy::type_complexity)]
 1389    selections_by_transaction:
 1390        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1391    mode: SelectionHistoryMode,
 1392    undo_stack: VecDeque<SelectionHistoryEntry>,
 1393    redo_stack: VecDeque<SelectionHistoryEntry>,
 1394}
 1395
 1396impl SelectionHistory {
 1397    #[track_caller]
 1398    fn insert_transaction(
 1399        &mut self,
 1400        transaction_id: TransactionId,
 1401        selections: Arc<[Selection<Anchor>]>,
 1402    ) {
 1403        if selections.is_empty() {
 1404            log::error!(
 1405                "SelectionHistory::insert_transaction called with empty selections. Caller: {}",
 1406                std::panic::Location::caller()
 1407            );
 1408            return;
 1409        }
 1410        self.selections_by_transaction
 1411            .insert(transaction_id, (selections, None));
 1412    }
 1413
 1414    #[allow(clippy::type_complexity)]
 1415    fn transaction(
 1416        &self,
 1417        transaction_id: TransactionId,
 1418    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1419        self.selections_by_transaction.get(&transaction_id)
 1420    }
 1421
 1422    #[allow(clippy::type_complexity)]
 1423    fn transaction_mut(
 1424        &mut self,
 1425        transaction_id: TransactionId,
 1426    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1427        self.selections_by_transaction.get_mut(&transaction_id)
 1428    }
 1429
 1430    fn push(&mut self, entry: SelectionHistoryEntry) {
 1431        if !entry.selections.is_empty() {
 1432            match self.mode {
 1433                SelectionHistoryMode::Normal => {
 1434                    self.push_undo(entry);
 1435                    self.redo_stack.clear();
 1436                }
 1437                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1438                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1439                SelectionHistoryMode::Skipping => {}
 1440            }
 1441        }
 1442    }
 1443
 1444    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1445        if self
 1446            .undo_stack
 1447            .back()
 1448            .is_none_or(|e| e.selections != entry.selections)
 1449        {
 1450            self.undo_stack.push_back(entry);
 1451            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1452                self.undo_stack.pop_front();
 1453            }
 1454        }
 1455    }
 1456
 1457    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1458        if self
 1459            .redo_stack
 1460            .back()
 1461            .is_none_or(|e| e.selections != entry.selections)
 1462        {
 1463            self.redo_stack.push_back(entry);
 1464            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1465                self.redo_stack.pop_front();
 1466            }
 1467        }
 1468    }
 1469}
 1470
 1471#[derive(Clone, Copy)]
 1472pub struct RowHighlightOptions {
 1473    pub autoscroll: bool,
 1474    pub include_gutter: bool,
 1475}
 1476
 1477impl Default for RowHighlightOptions {
 1478    fn default() -> Self {
 1479        Self {
 1480            autoscroll: Default::default(),
 1481            include_gutter: true,
 1482        }
 1483    }
 1484}
 1485
 1486struct RowHighlight {
 1487    index: usize,
 1488    range: Range<Anchor>,
 1489    color: Hsla,
 1490    options: RowHighlightOptions,
 1491    type_id: TypeId,
 1492}
 1493
 1494#[derive(Clone, Debug)]
 1495struct AddSelectionsState {
 1496    groups: Vec<AddSelectionsGroup>,
 1497}
 1498
 1499#[derive(Clone, Debug)]
 1500struct AddSelectionsGroup {
 1501    above: bool,
 1502    stack: Vec<usize>,
 1503}
 1504
 1505#[derive(Clone)]
 1506struct SelectNextState {
 1507    query: AhoCorasick,
 1508    wordwise: bool,
 1509    done: bool,
 1510}
 1511
 1512impl std::fmt::Debug for SelectNextState {
 1513    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1514        f.debug_struct(std::any::type_name::<Self>())
 1515            .field("wordwise", &self.wordwise)
 1516            .field("done", &self.done)
 1517            .finish()
 1518    }
 1519}
 1520
 1521#[derive(Debug)]
 1522struct AutocloseRegion {
 1523    selection_id: usize,
 1524    range: Range<Anchor>,
 1525    pair: BracketPair,
 1526}
 1527
 1528#[derive(Debug)]
 1529struct SnippetState {
 1530    ranges: Vec<Vec<Range<Anchor>>>,
 1531    active_index: usize,
 1532    choices: Vec<Option<Vec<String>>>,
 1533}
 1534
 1535#[doc(hidden)]
 1536pub struct RenameState {
 1537    pub range: Range<Anchor>,
 1538    pub old_name: Arc<str>,
 1539    pub editor: Entity<Editor>,
 1540    block_id: CustomBlockId,
 1541}
 1542
 1543struct InvalidationStack<T>(Vec<T>);
 1544
 1545struct RegisteredEditPredictionProvider {
 1546    provider: Arc<dyn EditPredictionProviderHandle>,
 1547    _subscription: Subscription,
 1548}
 1549
 1550#[derive(Debug, PartialEq, Eq)]
 1551pub struct ActiveDiagnosticGroup {
 1552    pub active_range: Range<Anchor>,
 1553    pub active_message: String,
 1554    pub group_id: usize,
 1555    pub blocks: HashSet<CustomBlockId>,
 1556}
 1557
 1558#[derive(Debug, PartialEq, Eq)]
 1559
 1560pub(crate) enum ActiveDiagnostic {
 1561    None,
 1562    All,
 1563    Group(ActiveDiagnosticGroup),
 1564}
 1565
 1566#[derive(Serialize, Deserialize, Clone, Debug)]
 1567pub struct ClipboardSelection {
 1568    /// The number of bytes in this selection.
 1569    pub len: usize,
 1570    /// Whether this was a full-line selection.
 1571    pub is_entire_line: bool,
 1572    /// The indentation of the first line when this content was originally copied.
 1573    pub first_line_indent: u32,
 1574}
 1575
 1576// selections, scroll behavior, was newest selection reversed
 1577type SelectSyntaxNodeHistoryState = (
 1578    Box<[Selection<usize>]>,
 1579    SelectSyntaxNodeScrollBehavior,
 1580    bool,
 1581);
 1582
 1583#[derive(Default)]
 1584struct SelectSyntaxNodeHistory {
 1585    stack: Vec<SelectSyntaxNodeHistoryState>,
 1586    // disable temporarily to allow changing selections without losing the stack
 1587    pub disable_clearing: bool,
 1588}
 1589
 1590impl SelectSyntaxNodeHistory {
 1591    pub fn try_clear(&mut self) {
 1592        if !self.disable_clearing {
 1593            self.stack.clear();
 1594        }
 1595    }
 1596
 1597    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1598        self.stack.push(selection);
 1599    }
 1600
 1601    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1602        self.stack.pop()
 1603    }
 1604}
 1605
 1606enum SelectSyntaxNodeScrollBehavior {
 1607    CursorTop,
 1608    FitSelection,
 1609    CursorBottom,
 1610}
 1611
 1612#[derive(Debug)]
 1613pub(crate) struct NavigationData {
 1614    cursor_anchor: Anchor,
 1615    cursor_position: Point,
 1616    scroll_anchor: ScrollAnchor,
 1617    scroll_top_row: u32,
 1618}
 1619
 1620#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1621pub enum GotoDefinitionKind {
 1622    Symbol,
 1623    Declaration,
 1624    Type,
 1625    Implementation,
 1626}
 1627
 1628pub enum FormatTarget {
 1629    Buffers(HashSet<Entity<Buffer>>),
 1630    Ranges(Vec<Range<MultiBufferPoint>>),
 1631}
 1632
 1633pub(crate) struct FocusedBlock {
 1634    id: BlockId,
 1635    focus_handle: WeakFocusHandle,
 1636}
 1637
 1638#[derive(Clone)]
 1639enum JumpData {
 1640    MultiBufferRow {
 1641        row: MultiBufferRow,
 1642        line_offset_from_top: u32,
 1643    },
 1644    MultiBufferPoint {
 1645        excerpt_id: ExcerptId,
 1646        position: Point,
 1647        anchor: text::Anchor,
 1648        line_offset_from_top: u32,
 1649    },
 1650}
 1651
 1652pub enum MultibufferSelectionMode {
 1653    First,
 1654    All,
 1655}
 1656
 1657#[derive(Clone, Copy, Debug, Default)]
 1658pub struct RewrapOptions {
 1659    pub override_language_settings: bool,
 1660    pub preserve_existing_whitespace: bool,
 1661}
 1662
 1663impl Editor {
 1664    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1665        let buffer = cx.new(|cx| Buffer::local("", cx));
 1666        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1667        Self::new(EditorMode::SingleLine, buffer, None, window, cx)
 1668    }
 1669
 1670    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1671        let buffer = cx.new(|cx| Buffer::local("", cx));
 1672        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1673        Self::new(EditorMode::full(), buffer, None, window, cx)
 1674    }
 1675
 1676    pub fn auto_height(
 1677        min_lines: usize,
 1678        max_lines: usize,
 1679        window: &mut Window,
 1680        cx: &mut Context<Self>,
 1681    ) -> Self {
 1682        let buffer = cx.new(|cx| Buffer::local("", cx));
 1683        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1684        Self::new(
 1685            EditorMode::AutoHeight {
 1686                min_lines,
 1687                max_lines: Some(max_lines),
 1688            },
 1689            buffer,
 1690            None,
 1691            window,
 1692            cx,
 1693        )
 1694    }
 1695
 1696    /// Creates a new auto-height editor with a minimum number of lines but no maximum.
 1697    /// The editor grows as tall as needed to fit its content.
 1698    pub fn auto_height_unbounded(
 1699        min_lines: usize,
 1700        window: &mut Window,
 1701        cx: &mut Context<Self>,
 1702    ) -> Self {
 1703        let buffer = cx.new(|cx| Buffer::local("", cx));
 1704        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1705        Self::new(
 1706            EditorMode::AutoHeight {
 1707                min_lines,
 1708                max_lines: None,
 1709            },
 1710            buffer,
 1711            None,
 1712            window,
 1713            cx,
 1714        )
 1715    }
 1716
 1717    pub fn for_buffer(
 1718        buffer: Entity<Buffer>,
 1719        project: Option<Entity<Project>>,
 1720        window: &mut Window,
 1721        cx: &mut Context<Self>,
 1722    ) -> Self {
 1723        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1724        Self::new(EditorMode::full(), buffer, project, window, cx)
 1725    }
 1726
 1727    pub fn for_multibuffer(
 1728        buffer: Entity<MultiBuffer>,
 1729        project: Option<Entity<Project>>,
 1730        window: &mut Window,
 1731        cx: &mut Context<Self>,
 1732    ) -> Self {
 1733        Self::new(EditorMode::full(), buffer, project, window, cx)
 1734    }
 1735
 1736    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1737        let mut clone = Self::new(
 1738            self.mode.clone(),
 1739            self.buffer.clone(),
 1740            self.project.clone(),
 1741            window,
 1742            cx,
 1743        );
 1744        self.display_map.update(cx, |display_map, cx| {
 1745            let snapshot = display_map.snapshot(cx);
 1746            clone.display_map.update(cx, |display_map, cx| {
 1747                display_map.set_state(&snapshot, cx);
 1748            });
 1749        });
 1750        clone.folds_did_change(cx);
 1751        clone.selections.clone_state(&self.selections);
 1752        clone.scroll_manager.clone_state(&self.scroll_manager);
 1753        clone.searchable = self.searchable;
 1754        clone.read_only = self.read_only;
 1755        clone
 1756    }
 1757
 1758    pub fn new(
 1759        mode: EditorMode,
 1760        buffer: Entity<MultiBuffer>,
 1761        project: Option<Entity<Project>>,
 1762        window: &mut Window,
 1763        cx: &mut Context<Self>,
 1764    ) -> Self {
 1765        Editor::new_internal(mode, buffer, project, None, window, cx)
 1766    }
 1767
 1768    pub fn sticky_headers(&self, cx: &App) -> Option<Vec<OutlineItem<Anchor>>> {
 1769        let multi_buffer = self.buffer().read(cx);
 1770        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 1771        let multi_buffer_visible_start = self
 1772            .scroll_manager
 1773            .anchor()
 1774            .anchor
 1775            .to_point(&multi_buffer_snapshot);
 1776        let max_row = multi_buffer_snapshot.max_point().row;
 1777
 1778        let start_row = (multi_buffer_visible_start.row).min(max_row);
 1779        let end_row = (multi_buffer_visible_start.row + 10).min(max_row);
 1780
 1781        if let Some((excerpt_id, buffer_id, buffer)) = multi_buffer.read(cx).as_singleton() {
 1782            let outline_items = buffer
 1783                .outline_items_containing(
 1784                    Point::new(start_row, 0)..Point::new(end_row, 0),
 1785                    true,
 1786                    self.style().map(|style| style.syntax.as_ref()),
 1787                )
 1788                .into_iter()
 1789                .map(|outline_item| OutlineItem {
 1790                    depth: outline_item.depth,
 1791                    range: Anchor::range_in_buffer(*excerpt_id, buffer_id, outline_item.range),
 1792                    source_range_for_text: Anchor::range_in_buffer(
 1793                        *excerpt_id,
 1794                        buffer_id,
 1795                        outline_item.source_range_for_text,
 1796                    ),
 1797                    text: outline_item.text,
 1798                    highlight_ranges: outline_item.highlight_ranges,
 1799                    name_ranges: outline_item.name_ranges,
 1800                    body_range: outline_item
 1801                        .body_range
 1802                        .map(|range| Anchor::range_in_buffer(*excerpt_id, buffer_id, range)),
 1803                    annotation_range: outline_item
 1804                        .annotation_range
 1805                        .map(|range| Anchor::range_in_buffer(*excerpt_id, buffer_id, range)),
 1806                });
 1807            return Some(outline_items.collect());
 1808        }
 1809
 1810        None
 1811    }
 1812
 1813    fn new_internal(
 1814        mode: EditorMode,
 1815        multi_buffer: Entity<MultiBuffer>,
 1816        project: Option<Entity<Project>>,
 1817        display_map: Option<Entity<DisplayMap>>,
 1818        window: &mut Window,
 1819        cx: &mut Context<Self>,
 1820    ) -> Self {
 1821        debug_assert!(
 1822            display_map.is_none() || mode.is_minimap(),
 1823            "Providing a display map for a new editor is only intended for the minimap and might have unintended side effects otherwise!"
 1824        );
 1825
 1826        let full_mode = mode.is_full();
 1827        let is_minimap = mode.is_minimap();
 1828        let diagnostics_max_severity = if full_mode {
 1829            EditorSettings::get_global(cx)
 1830                .diagnostics_max_severity
 1831                .unwrap_or(DiagnosticSeverity::Hint)
 1832        } else {
 1833            DiagnosticSeverity::Off
 1834        };
 1835        let style = window.text_style();
 1836        let font_size = style.font_size.to_pixels(window.rem_size());
 1837        let editor = cx.entity().downgrade();
 1838        let fold_placeholder = FoldPlaceholder {
 1839            constrain_width: false,
 1840            render: Arc::new(move |fold_id, fold_range, cx| {
 1841                let editor = editor.clone();
 1842                div()
 1843                    .id(fold_id)
 1844                    .bg(cx.theme().colors().ghost_element_background)
 1845                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1846                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1847                    .rounded_xs()
 1848                    .size_full()
 1849                    .cursor_pointer()
 1850                    .child("")
 1851                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1852                    .on_click(move |_, _window, cx| {
 1853                        editor
 1854                            .update(cx, |editor, cx| {
 1855                                editor.unfold_ranges(
 1856                                    &[fold_range.start..fold_range.end],
 1857                                    true,
 1858                                    false,
 1859                                    cx,
 1860                                );
 1861                                cx.stop_propagation();
 1862                            })
 1863                            .ok();
 1864                    })
 1865                    .into_any()
 1866            }),
 1867            merge_adjacent: true,
 1868            ..FoldPlaceholder::default()
 1869        };
 1870        let display_map = display_map.unwrap_or_else(|| {
 1871            cx.new(|cx| {
 1872                DisplayMap::new(
 1873                    multi_buffer.clone(),
 1874                    style.font(),
 1875                    font_size,
 1876                    None,
 1877                    FILE_HEADER_HEIGHT,
 1878                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1879                    fold_placeholder,
 1880                    diagnostics_max_severity,
 1881                    cx,
 1882                )
 1883            })
 1884        });
 1885
 1886        let selections = SelectionsCollection::new();
 1887
 1888        let blink_manager = cx.new(|cx| {
 1889            let mut blink_manager = BlinkManager::new(CURSOR_BLINK_INTERVAL, cx);
 1890            if is_minimap {
 1891                blink_manager.disable(cx);
 1892            }
 1893            blink_manager
 1894        });
 1895
 1896        let soft_wrap_mode_override =
 1897            matches!(mode, EditorMode::SingleLine).then(|| language_settings::SoftWrap::None);
 1898
 1899        let mut project_subscriptions = Vec::new();
 1900        if full_mode && let Some(project) = project.as_ref() {
 1901            project_subscriptions.push(cx.subscribe_in(
 1902                project,
 1903                window,
 1904                |editor, _, event, window, cx| match event {
 1905                    project::Event::RefreshCodeLens => {
 1906                        // we always query lens with actions, without storing them, always refreshing them
 1907                    }
 1908                    project::Event::RefreshInlayHints {
 1909                        server_id,
 1910                        request_id,
 1911                    } => {
 1912                        editor.refresh_inlay_hints(
 1913                            InlayHintRefreshReason::RefreshRequested {
 1914                                server_id: *server_id,
 1915                                request_id: *request_id,
 1916                            },
 1917                            cx,
 1918                        );
 1919                    }
 1920                    project::Event::LanguageServerRemoved(..) => {
 1921                        if editor.tasks_update_task.is_none() {
 1922                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1923                        }
 1924                        editor.registered_buffers.clear();
 1925                        editor.register_visible_buffers(cx);
 1926                    }
 1927                    project::Event::LanguageServerAdded(..) => {
 1928                        if editor.tasks_update_task.is_none() {
 1929                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1930                        }
 1931                    }
 1932                    project::Event::SnippetEdit(id, snippet_edits) => {
 1933                        if let Some(buffer) = editor.buffer.read(cx).buffer(*id) {
 1934                            let focus_handle = editor.focus_handle(cx);
 1935                            if focus_handle.is_focused(window) {
 1936                                let snapshot = buffer.read(cx).snapshot();
 1937                                for (range, snippet) in snippet_edits {
 1938                                    let editor_range =
 1939                                        language::range_from_lsp(*range).to_offset(&snapshot);
 1940                                    editor
 1941                                        .insert_snippet(
 1942                                            &[editor_range],
 1943                                            snippet.clone(),
 1944                                            window,
 1945                                            cx,
 1946                                        )
 1947                                        .ok();
 1948                                }
 1949                            }
 1950                        }
 1951                    }
 1952                    project::Event::LanguageServerBufferRegistered { buffer_id, .. } => {
 1953                        let buffer_id = *buffer_id;
 1954                        if editor.buffer().read(cx).buffer(buffer_id).is_some() {
 1955                            editor.register_buffer(buffer_id, cx);
 1956                            editor.update_lsp_data(Some(buffer_id), window, cx);
 1957                            editor.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
 1958                            refresh_linked_ranges(editor, window, cx);
 1959                            editor.refresh_code_actions(window, cx);
 1960                            editor.refresh_document_highlights(cx);
 1961                        }
 1962                    }
 1963
 1964                    project::Event::EntryRenamed(transaction, project_path, abs_path) => {
 1965                        let Some(workspace) = editor.workspace() else {
 1966                            return;
 1967                        };
 1968                        let Some(active_editor) = workspace.read(cx).active_item_as::<Self>(cx)
 1969                        else {
 1970                            return;
 1971                        };
 1972
 1973                        if active_editor.entity_id() == cx.entity_id() {
 1974                            let entity_id = cx.entity_id();
 1975                            workspace.update(cx, |this, cx| {
 1976                                this.panes_mut()
 1977                                    .iter_mut()
 1978                                    .filter(|pane| pane.entity_id() != entity_id)
 1979                                    .for_each(|p| {
 1980                                        p.update(cx, |pane, _| {
 1981                                            pane.nav_history_mut().rename_item(
 1982                                                entity_id,
 1983                                                project_path.clone(),
 1984                                                abs_path.clone().into(),
 1985                                            );
 1986                                        })
 1987                                    });
 1988                            });
 1989                            let edited_buffers_already_open = {
 1990                                let other_editors: Vec<Entity<Editor>> = workspace
 1991                                    .read(cx)
 1992                                    .panes()
 1993                                    .iter()
 1994                                    .flat_map(|pane| pane.read(cx).items_of_type::<Editor>())
 1995                                    .filter(|editor| editor.entity_id() != cx.entity_id())
 1996                                    .collect();
 1997
 1998                                transaction.0.keys().all(|buffer| {
 1999                                    other_editors.iter().any(|editor| {
 2000                                        let multi_buffer = editor.read(cx).buffer();
 2001                                        multi_buffer.read(cx).is_singleton()
 2002                                            && multi_buffer.read(cx).as_singleton().map_or(
 2003                                                false,
 2004                                                |singleton| {
 2005                                                    singleton.entity_id() == buffer.entity_id()
 2006                                                },
 2007                                            )
 2008                                    })
 2009                                })
 2010                            };
 2011                            if !edited_buffers_already_open {
 2012                                let workspace = workspace.downgrade();
 2013                                let transaction = transaction.clone();
 2014                                cx.defer_in(window, move |_, window, cx| {
 2015                                    cx.spawn_in(window, async move |editor, cx| {
 2016                                        Self::open_project_transaction(
 2017                                            &editor,
 2018                                            workspace,
 2019                                            transaction,
 2020                                            "Rename".to_string(),
 2021                                            cx,
 2022                                        )
 2023                                        .await
 2024                                        .ok()
 2025                                    })
 2026                                    .detach();
 2027                                });
 2028                            }
 2029                        }
 2030                    }
 2031
 2032                    _ => {}
 2033                },
 2034            ));
 2035            if let Some(task_inventory) = project
 2036                .read(cx)
 2037                .task_store()
 2038                .read(cx)
 2039                .task_inventory()
 2040                .cloned()
 2041            {
 2042                project_subscriptions.push(cx.observe_in(
 2043                    &task_inventory,
 2044                    window,
 2045                    |editor, _, window, cx| {
 2046                        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2047                    },
 2048                ));
 2049            };
 2050
 2051            project_subscriptions.push(cx.subscribe_in(
 2052                &project.read(cx).breakpoint_store(),
 2053                window,
 2054                |editor, _, event, window, cx| match event {
 2055                    BreakpointStoreEvent::ClearDebugLines => {
 2056                        editor.clear_row_highlights::<ActiveDebugLine>();
 2057                        editor.refresh_inline_values(cx);
 2058                    }
 2059                    BreakpointStoreEvent::SetDebugLine => {
 2060                        if editor.go_to_active_debug_line(window, cx) {
 2061                            cx.stop_propagation();
 2062                        }
 2063
 2064                        editor.refresh_inline_values(cx);
 2065                    }
 2066                    _ => {}
 2067                },
 2068            ));
 2069            let git_store = project.read(cx).git_store().clone();
 2070            let project = project.clone();
 2071            project_subscriptions.push(cx.subscribe(&git_store, move |this, _, event, cx| {
 2072                if let GitStoreEvent::RepositoryAdded = event {
 2073                    this.load_diff_task = Some(
 2074                        update_uncommitted_diff_for_buffer(
 2075                            cx.entity(),
 2076                            &project,
 2077                            this.buffer.read(cx).all_buffers(),
 2078                            this.buffer.clone(),
 2079                            cx,
 2080                        )
 2081                        .shared(),
 2082                    );
 2083                }
 2084            }));
 2085        }
 2086
 2087        let buffer_snapshot = multi_buffer.read(cx).snapshot(cx);
 2088
 2089        let inlay_hint_settings =
 2090            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 2091        let focus_handle = cx.focus_handle();
 2092        if !is_minimap {
 2093            cx.on_focus(&focus_handle, window, Self::handle_focus)
 2094                .detach();
 2095            cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 2096                .detach();
 2097            cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 2098                .detach();
 2099            cx.on_blur(&focus_handle, window, Self::handle_blur)
 2100                .detach();
 2101            cx.observe_pending_input(window, Self::observe_pending_input)
 2102                .detach();
 2103        }
 2104
 2105        let show_indent_guides =
 2106            if matches!(mode, EditorMode::SingleLine | EditorMode::Minimap { .. }) {
 2107                Some(false)
 2108            } else {
 2109                None
 2110            };
 2111
 2112        let breakpoint_store = match (&mode, project.as_ref()) {
 2113            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 2114            _ => None,
 2115        };
 2116
 2117        let mut code_action_providers = Vec::new();
 2118        let mut load_uncommitted_diff = None;
 2119        if let Some(project) = project.clone() {
 2120            load_uncommitted_diff = Some(
 2121                update_uncommitted_diff_for_buffer(
 2122                    cx.entity(),
 2123                    &project,
 2124                    multi_buffer.read(cx).all_buffers(),
 2125                    multi_buffer.clone(),
 2126                    cx,
 2127                )
 2128                .shared(),
 2129            );
 2130            code_action_providers.push(Rc::new(project) as Rc<_>);
 2131        }
 2132
 2133        let mut editor = Self {
 2134            focus_handle,
 2135            show_cursor_when_unfocused: false,
 2136            last_focused_descendant: None,
 2137            buffer: multi_buffer.clone(),
 2138            display_map: display_map.clone(),
 2139            placeholder_display_map: None,
 2140            selections,
 2141            scroll_manager: ScrollManager::new(cx),
 2142            columnar_selection_state: None,
 2143            add_selections_state: None,
 2144            select_next_state: None,
 2145            select_prev_state: None,
 2146            selection_history: SelectionHistory::default(),
 2147            defer_selection_effects: false,
 2148            deferred_selection_effects_state: None,
 2149            autoclose_regions: Vec::new(),
 2150            snippet_stack: InvalidationStack::default(),
 2151            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 2152            ime_transaction: None,
 2153            active_diagnostics: ActiveDiagnostic::None,
 2154            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 2155            inline_diagnostics_update: Task::ready(()),
 2156            inline_diagnostics: Vec::new(),
 2157            soft_wrap_mode_override,
 2158            diagnostics_max_severity,
 2159            hard_wrap: None,
 2160            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 2161            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 2162            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 2163            project,
 2164            blink_manager: blink_manager.clone(),
 2165            show_local_selections: true,
 2166            show_scrollbars: ScrollbarAxes {
 2167                horizontal: full_mode,
 2168                vertical: full_mode,
 2169            },
 2170            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 2171            offset_content: !matches!(mode, EditorMode::SingleLine),
 2172            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 2173            show_gutter: full_mode,
 2174            show_line_numbers: (!full_mode).then_some(false),
 2175            use_relative_line_numbers: None,
 2176            disable_expand_excerpt_buttons: !full_mode,
 2177            show_git_diff_gutter: None,
 2178            show_code_actions: None,
 2179            show_runnables: None,
 2180            show_breakpoints: None,
 2181            show_wrap_guides: None,
 2182            show_indent_guides,
 2183            highlight_order: 0,
 2184            highlighted_rows: HashMap::default(),
 2185            background_highlights: HashMap::default(),
 2186            gutter_highlights: HashMap::default(),
 2187            scrollbar_marker_state: ScrollbarMarkerState::default(),
 2188            active_indent_guides_state: ActiveIndentGuidesState::default(),
 2189            nav_history: None,
 2190            context_menu: RefCell::new(None),
 2191            context_menu_options: None,
 2192            mouse_context_menu: None,
 2193            completion_tasks: Vec::new(),
 2194            inline_blame_popover: None,
 2195            inline_blame_popover_show_task: None,
 2196            signature_help_state: SignatureHelpState::default(),
 2197            auto_signature_help: None,
 2198            find_all_references_task_sources: Vec::new(),
 2199            next_completion_id: 0,
 2200            next_inlay_id: 0,
 2201            code_action_providers,
 2202            available_code_actions: None,
 2203            code_actions_task: None,
 2204            quick_selection_highlight_task: None,
 2205            debounced_selection_highlight_task: None,
 2206            document_highlights_task: None,
 2207            linked_editing_range_task: None,
 2208            pending_rename: None,
 2209            searchable: !is_minimap,
 2210            cursor_shape: EditorSettings::get_global(cx)
 2211                .cursor_shape
 2212                .unwrap_or_default(),
 2213            current_line_highlight: None,
 2214            autoindent_mode: Some(AutoindentMode::EachLine),
 2215
 2216            workspace: None,
 2217            input_enabled: !is_minimap,
 2218            use_modal_editing: full_mode,
 2219            read_only: is_minimap,
 2220            use_autoclose: true,
 2221            use_auto_surround: true,
 2222            auto_replace_emoji_shortcode: false,
 2223            jsx_tag_auto_close_enabled_in_any_buffer: false,
 2224            leader_id: None,
 2225            remote_id: None,
 2226            hover_state: HoverState::default(),
 2227            pending_mouse_down: None,
 2228            hovered_link_state: None,
 2229            edit_prediction_provider: None,
 2230            active_edit_prediction: None,
 2231            stale_edit_prediction_in_menu: None,
 2232            edit_prediction_preview: EditPredictionPreview::Inactive {
 2233                released_too_fast: false,
 2234            },
 2235            inline_diagnostics_enabled: full_mode,
 2236            diagnostics_enabled: full_mode,
 2237            word_completions_enabled: full_mode,
 2238            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 2239            gutter_hovered: false,
 2240            pixel_position_of_newest_cursor: None,
 2241            last_bounds: None,
 2242            last_position_map: None,
 2243            expect_bounds_change: None,
 2244            gutter_dimensions: GutterDimensions::default(),
 2245            style: None,
 2246            show_cursor_names: false,
 2247            hovered_cursors: HashMap::default(),
 2248            next_editor_action_id: EditorActionId::default(),
 2249            editor_actions: Rc::default(),
 2250            edit_predictions_hidden_for_vim_mode: false,
 2251            show_edit_predictions_override: None,
 2252            menu_edit_predictions_policy: MenuEditPredictionsPolicy::ByProvider,
 2253            edit_prediction_settings: EditPredictionSettings::Disabled,
 2254            edit_prediction_indent_conflict: false,
 2255            edit_prediction_requires_modifier_in_indent_conflict: true,
 2256            custom_context_menu: None,
 2257            show_git_blame_gutter: false,
 2258            show_git_blame_inline: false,
 2259            show_selection_menu: None,
 2260            show_git_blame_inline_delay_task: None,
 2261            git_blame_inline_enabled: full_mode
 2262                && ProjectSettings::get_global(cx).git.inline_blame.enabled,
 2263            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 2264            buffer_serialization: is_minimap.not().then(|| {
 2265                BufferSerialization::new(
 2266                    ProjectSettings::get_global(cx)
 2267                        .session
 2268                        .restore_unsaved_buffers,
 2269                )
 2270            }),
 2271            blame: None,
 2272            blame_subscription: None,
 2273            tasks: BTreeMap::default(),
 2274
 2275            breakpoint_store,
 2276            gutter_breakpoint_indicator: (None, None),
 2277            hovered_diff_hunk_row: None,
 2278            _subscriptions: (!is_minimap)
 2279                .then(|| {
 2280                    vec![
 2281                        cx.observe(&multi_buffer, Self::on_buffer_changed),
 2282                        cx.subscribe_in(&multi_buffer, window, Self::on_buffer_event),
 2283                        cx.observe_in(&display_map, window, Self::on_display_map_changed),
 2284                        cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 2285                        cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 2286                        observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 2287                        cx.observe_window_activation(window, |editor, window, cx| {
 2288                            let active = window.is_window_active();
 2289                            editor.blink_manager.update(cx, |blink_manager, cx| {
 2290                                if active {
 2291                                    blink_manager.enable(cx);
 2292                                } else {
 2293                                    blink_manager.disable(cx);
 2294                                }
 2295                            });
 2296                            if active {
 2297                                editor.show_mouse_cursor(cx);
 2298                            }
 2299                        }),
 2300                    ]
 2301                })
 2302                .unwrap_or_default(),
 2303            tasks_update_task: None,
 2304            pull_diagnostics_task: Task::ready(()),
 2305            colors: None,
 2306            refresh_colors_task: Task::ready(()),
 2307            inlay_hints: None,
 2308            next_color_inlay_id: 0,
 2309            post_scroll_update: Task::ready(()),
 2310            linked_edit_ranges: Default::default(),
 2311            in_project_search: false,
 2312            previous_search_ranges: None,
 2313            breadcrumb_header: None,
 2314            focused_block: None,
 2315            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 2316            addons: HashMap::default(),
 2317            registered_buffers: HashMap::default(),
 2318            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 2319            selection_mark_mode: false,
 2320            toggle_fold_multiple_buffers: Task::ready(()),
 2321            serialize_selections: Task::ready(()),
 2322            serialize_folds: Task::ready(()),
 2323            text_style_refinement: None,
 2324            load_diff_task: load_uncommitted_diff,
 2325            temporary_diff_override: false,
 2326            mouse_cursor_hidden: false,
 2327            minimap: None,
 2328            hide_mouse_mode: EditorSettings::get_global(cx)
 2329                .hide_mouse
 2330                .unwrap_or_default(),
 2331            change_list: ChangeList::new(),
 2332            mode,
 2333            selection_drag_state: SelectionDragState::None,
 2334            folding_newlines: Task::ready(()),
 2335            lookup_key: None,
 2336        };
 2337
 2338        if is_minimap {
 2339            return editor;
 2340        }
 2341
 2342        if let Some(breakpoints) = editor.breakpoint_store.as_ref() {
 2343            editor
 2344                ._subscriptions
 2345                .push(cx.observe(breakpoints, |_, _, cx| {
 2346                    cx.notify();
 2347                }));
 2348        }
 2349        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2350        editor._subscriptions.extend(project_subscriptions);
 2351
 2352        editor._subscriptions.push(cx.subscribe_in(
 2353            &cx.entity(),
 2354            window,
 2355            |editor, _, e: &EditorEvent, window, cx| match e {
 2356                EditorEvent::ScrollPositionChanged { local, .. } => {
 2357                    if *local {
 2358                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 2359                        editor.inline_blame_popover.take();
 2360                        let new_anchor = editor.scroll_manager.anchor();
 2361                        let snapshot = editor.snapshot(window, cx);
 2362                        editor.update_restoration_data(cx, move |data| {
 2363                            data.scroll_position = (
 2364                                new_anchor.top_row(snapshot.buffer_snapshot()),
 2365                                new_anchor.offset,
 2366                            );
 2367                        });
 2368
 2369                        editor.post_scroll_update = cx.spawn_in(window, async move |editor, cx| {
 2370                            cx.background_executor()
 2371                                .timer(Duration::from_millis(50))
 2372                                .await;
 2373                            editor
 2374                                .update_in(cx, |editor, window, cx| {
 2375                                    editor.register_visible_buffers(cx);
 2376                                    editor.refresh_colors_for_visible_range(None, window, cx);
 2377                                    editor.refresh_inlay_hints(
 2378                                        InlayHintRefreshReason::NewLinesShown,
 2379                                        cx,
 2380                                    );
 2381                                })
 2382                                .ok();
 2383                        });
 2384                    }
 2385                }
 2386                EditorEvent::Edited { .. } => {
 2387                    if vim_flavor(cx).is_none() {
 2388                        let display_map = editor.display_snapshot(cx);
 2389                        let selections = editor.selections.all_adjusted_display(&display_map);
 2390                        let pop_state = editor
 2391                            .change_list
 2392                            .last()
 2393                            .map(|previous| {
 2394                                previous.len() == selections.len()
 2395                                    && previous.iter().enumerate().all(|(ix, p)| {
 2396                                        p.to_display_point(&display_map).row()
 2397                                            == selections[ix].head().row()
 2398                                    })
 2399                            })
 2400                            .unwrap_or(false);
 2401                        let new_positions = selections
 2402                            .into_iter()
 2403                            .map(|s| display_map.display_point_to_anchor(s.head(), Bias::Left))
 2404                            .collect();
 2405                        editor
 2406                            .change_list
 2407                            .push_to_change_list(pop_state, new_positions);
 2408                    }
 2409                }
 2410                _ => (),
 2411            },
 2412        ));
 2413
 2414        if let Some(dap_store) = editor
 2415            .project
 2416            .as_ref()
 2417            .map(|project| project.read(cx).dap_store())
 2418        {
 2419            let weak_editor = cx.weak_entity();
 2420
 2421            editor
 2422                ._subscriptions
 2423                .push(
 2424                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2425                        let session_entity = cx.entity();
 2426                        weak_editor
 2427                            .update(cx, |editor, cx| {
 2428                                editor._subscriptions.push(
 2429                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2430                                );
 2431                            })
 2432                            .ok();
 2433                    }),
 2434                );
 2435
 2436            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2437                editor
 2438                    ._subscriptions
 2439                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2440            }
 2441        }
 2442
 2443        // skip adding the initial selection to selection history
 2444        editor.selection_history.mode = SelectionHistoryMode::Skipping;
 2445        editor.end_selection(window, cx);
 2446        editor.selection_history.mode = SelectionHistoryMode::Normal;
 2447
 2448        editor.scroll_manager.show_scrollbars(window, cx);
 2449        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut editor, &multi_buffer, cx);
 2450
 2451        if full_mode {
 2452            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2453            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2454
 2455            if editor.git_blame_inline_enabled {
 2456                editor.start_git_blame_inline(false, window, cx);
 2457            }
 2458
 2459            editor.go_to_active_debug_line(window, cx);
 2460
 2461            editor.minimap =
 2462                editor.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2463            editor.colors = Some(LspColorData::new(cx));
 2464            editor.inlay_hints = Some(LspInlayHintData::new(inlay_hint_settings));
 2465
 2466            if let Some(buffer) = multi_buffer.read(cx).as_singleton() {
 2467                editor.register_buffer(buffer.read(cx).remote_id(), cx);
 2468            }
 2469            editor.update_lsp_data(None, window, cx);
 2470            editor.report_editor_event(ReportEditorEvent::EditorOpened, None, cx);
 2471        }
 2472
 2473        editor
 2474    }
 2475
 2476    pub fn display_snapshot(&self, cx: &mut App) -> DisplaySnapshot {
 2477        self.display_map.update(cx, |map, cx| map.snapshot(cx))
 2478    }
 2479
 2480    pub fn deploy_mouse_context_menu(
 2481        &mut self,
 2482        position: gpui::Point<Pixels>,
 2483        context_menu: Entity<ContextMenu>,
 2484        window: &mut Window,
 2485        cx: &mut Context<Self>,
 2486    ) {
 2487        self.mouse_context_menu = Some(MouseContextMenu::new(
 2488            self,
 2489            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2490            context_menu,
 2491            window,
 2492            cx,
 2493        ));
 2494    }
 2495
 2496    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2497        self.mouse_context_menu
 2498            .as_ref()
 2499            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2500    }
 2501
 2502    pub fn is_range_selected(&mut self, range: &Range<Anchor>, cx: &mut Context<Self>) -> bool {
 2503        if self
 2504            .selections
 2505            .pending_anchor()
 2506            .is_some_and(|pending_selection| {
 2507                let snapshot = self.buffer().read(cx).snapshot(cx);
 2508                pending_selection.range().includes(range, &snapshot)
 2509            })
 2510        {
 2511            return true;
 2512        }
 2513
 2514        self.selections
 2515            .disjoint_in_range::<usize>(range.clone(), &self.display_snapshot(cx))
 2516            .into_iter()
 2517            .any(|selection| {
 2518                // This is needed to cover a corner case, if we just check for an existing
 2519                // selection in the fold range, having a cursor at the start of the fold
 2520                // marks it as selected. Non-empty selections don't cause this.
 2521                let length = selection.end - selection.start;
 2522                length > 0
 2523            })
 2524    }
 2525
 2526    pub fn key_context(&self, window: &mut Window, cx: &mut App) -> KeyContext {
 2527        self.key_context_internal(self.has_active_edit_prediction(), window, cx)
 2528    }
 2529
 2530    fn key_context_internal(
 2531        &self,
 2532        has_active_edit_prediction: bool,
 2533        window: &mut Window,
 2534        cx: &mut App,
 2535    ) -> KeyContext {
 2536        let mut key_context = KeyContext::new_with_defaults();
 2537        key_context.add("Editor");
 2538        let mode = match self.mode {
 2539            EditorMode::SingleLine => "single_line",
 2540            EditorMode::AutoHeight { .. } => "auto_height",
 2541            EditorMode::Minimap { .. } => "minimap",
 2542            EditorMode::Full { .. } => "full",
 2543        };
 2544
 2545        if EditorSettings::jupyter_enabled(cx) {
 2546            key_context.add("jupyter");
 2547        }
 2548
 2549        key_context.set("mode", mode);
 2550        if self.pending_rename.is_some() {
 2551            key_context.add("renaming");
 2552        }
 2553
 2554        if let Some(snippet_stack) = self.snippet_stack.last() {
 2555            key_context.add("in_snippet");
 2556
 2557            if snippet_stack.active_index > 0 {
 2558                key_context.add("has_previous_tabstop");
 2559            }
 2560
 2561            if snippet_stack.active_index < snippet_stack.ranges.len().saturating_sub(1) {
 2562                key_context.add("has_next_tabstop");
 2563            }
 2564        }
 2565
 2566        match self.context_menu.borrow().as_ref() {
 2567            Some(CodeContextMenu::Completions(menu)) => {
 2568                if menu.visible() {
 2569                    key_context.add("menu");
 2570                    key_context.add("showing_completions");
 2571                }
 2572            }
 2573            Some(CodeContextMenu::CodeActions(menu)) => {
 2574                if menu.visible() {
 2575                    key_context.add("menu");
 2576                    key_context.add("showing_code_actions")
 2577                }
 2578            }
 2579            None => {}
 2580        }
 2581
 2582        if self.signature_help_state.has_multiple_signatures() {
 2583            key_context.add("showing_signature_help");
 2584        }
 2585
 2586        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2587        if !self.focus_handle(cx).contains_focused(window, cx)
 2588            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2589        {
 2590            for addon in self.addons.values() {
 2591                addon.extend_key_context(&mut key_context, cx)
 2592            }
 2593        }
 2594
 2595        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2596            if let Some(extension) = singleton_buffer.read(cx).file().and_then(|file| {
 2597                Some(
 2598                    file.full_path(cx)
 2599                        .extension()?
 2600                        .to_string_lossy()
 2601                        .into_owned(),
 2602                )
 2603            }) {
 2604                key_context.set("extension", extension);
 2605            }
 2606        } else {
 2607            key_context.add("multibuffer");
 2608        }
 2609
 2610        if has_active_edit_prediction {
 2611            if self.edit_prediction_in_conflict() {
 2612                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2613            } else {
 2614                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2615                key_context.add("copilot_suggestion");
 2616            }
 2617        }
 2618
 2619        if self.selection_mark_mode {
 2620            key_context.add("selection_mode");
 2621        }
 2622
 2623        let disjoint = self.selections.disjoint_anchors();
 2624        let snapshot = self.snapshot(window, cx);
 2625        let snapshot = snapshot.buffer_snapshot();
 2626        if self.mode == EditorMode::SingleLine
 2627            && let [selection] = disjoint
 2628            && selection.start == selection.end
 2629            && selection.end.to_offset(snapshot) == snapshot.len()
 2630        {
 2631            key_context.add("end_of_input");
 2632        }
 2633
 2634        key_context
 2635    }
 2636
 2637    pub fn last_bounds(&self) -> Option<&Bounds<Pixels>> {
 2638        self.last_bounds.as_ref()
 2639    }
 2640
 2641    fn show_mouse_cursor(&mut self, cx: &mut Context<Self>) {
 2642        if self.mouse_cursor_hidden {
 2643            self.mouse_cursor_hidden = false;
 2644            cx.notify();
 2645        }
 2646    }
 2647
 2648    pub fn hide_mouse_cursor(&mut self, origin: HideMouseCursorOrigin, cx: &mut Context<Self>) {
 2649        let hide_mouse_cursor = match origin {
 2650            HideMouseCursorOrigin::TypingAction => {
 2651                matches!(
 2652                    self.hide_mouse_mode,
 2653                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2654                )
 2655            }
 2656            HideMouseCursorOrigin::MovementAction => {
 2657                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2658            }
 2659        };
 2660        if self.mouse_cursor_hidden != hide_mouse_cursor {
 2661            self.mouse_cursor_hidden = hide_mouse_cursor;
 2662            cx.notify();
 2663        }
 2664    }
 2665
 2666    pub fn edit_prediction_in_conflict(&self) -> bool {
 2667        if !self.show_edit_predictions_in_menu() {
 2668            return false;
 2669        }
 2670
 2671        let showing_completions = self
 2672            .context_menu
 2673            .borrow()
 2674            .as_ref()
 2675            .is_some_and(|context| matches!(context, CodeContextMenu::Completions(_)));
 2676
 2677        showing_completions
 2678            || self.edit_prediction_requires_modifier()
 2679            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2680            // bindings to insert tab characters.
 2681            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2682    }
 2683
 2684    pub fn accept_edit_prediction_keybind(
 2685        &self,
 2686        accept_partial: bool,
 2687        window: &mut Window,
 2688        cx: &mut App,
 2689    ) -> AcceptEditPredictionBinding {
 2690        let key_context = self.key_context_internal(true, window, cx);
 2691        let in_conflict = self.edit_prediction_in_conflict();
 2692
 2693        let bindings = if accept_partial {
 2694            window.bindings_for_action_in_context(&AcceptPartialEditPrediction, key_context)
 2695        } else {
 2696            window.bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2697        };
 2698
 2699        // TODO: if the binding contains multiple keystrokes, display all of them, not
 2700        // just the first one.
 2701        AcceptEditPredictionBinding(bindings.into_iter().rev().find(|binding| {
 2702            !in_conflict
 2703                || binding
 2704                    .keystrokes()
 2705                    .first()
 2706                    .is_some_and(|keystroke| keystroke.modifiers().modified())
 2707        }))
 2708    }
 2709
 2710    pub fn new_file(
 2711        workspace: &mut Workspace,
 2712        _: &workspace::NewFile,
 2713        window: &mut Window,
 2714        cx: &mut Context<Workspace>,
 2715    ) {
 2716        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2717            "Failed to create buffer",
 2718            window,
 2719            cx,
 2720            |e, _, _| match e.error_code() {
 2721                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2722                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2723                e.error_tag("required").unwrap_or("the latest version")
 2724            )),
 2725                _ => None,
 2726            },
 2727        );
 2728    }
 2729
 2730    pub fn new_in_workspace(
 2731        workspace: &mut Workspace,
 2732        window: &mut Window,
 2733        cx: &mut Context<Workspace>,
 2734    ) -> Task<Result<Entity<Editor>>> {
 2735        let project = workspace.project().clone();
 2736        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2737
 2738        cx.spawn_in(window, async move |workspace, cx| {
 2739            let buffer = create.await?;
 2740            workspace.update_in(cx, |workspace, window, cx| {
 2741                let editor =
 2742                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2743                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2744                editor
 2745            })
 2746        })
 2747    }
 2748
 2749    fn new_file_vertical(
 2750        workspace: &mut Workspace,
 2751        _: &workspace::NewFileSplitVertical,
 2752        window: &mut Window,
 2753        cx: &mut Context<Workspace>,
 2754    ) {
 2755        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2756    }
 2757
 2758    fn new_file_horizontal(
 2759        workspace: &mut Workspace,
 2760        _: &workspace::NewFileSplitHorizontal,
 2761        window: &mut Window,
 2762        cx: &mut Context<Workspace>,
 2763    ) {
 2764        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2765    }
 2766
 2767    fn new_file_split(
 2768        workspace: &mut Workspace,
 2769        action: &workspace::NewFileSplit,
 2770        window: &mut Window,
 2771        cx: &mut Context<Workspace>,
 2772    ) {
 2773        Self::new_file_in_direction(workspace, action.0, window, cx)
 2774    }
 2775
 2776    fn new_file_in_direction(
 2777        workspace: &mut Workspace,
 2778        direction: SplitDirection,
 2779        window: &mut Window,
 2780        cx: &mut Context<Workspace>,
 2781    ) {
 2782        let project = workspace.project().clone();
 2783        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2784
 2785        cx.spawn_in(window, async move |workspace, cx| {
 2786            let buffer = create.await?;
 2787            workspace.update_in(cx, move |workspace, window, cx| {
 2788                workspace.split_item(
 2789                    direction,
 2790                    Box::new(
 2791                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2792                    ),
 2793                    window,
 2794                    cx,
 2795                )
 2796            })?;
 2797            anyhow::Ok(())
 2798        })
 2799        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2800            match e.error_code() {
 2801                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2802                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2803                e.error_tag("required").unwrap_or("the latest version")
 2804            )),
 2805                _ => None,
 2806            }
 2807        });
 2808    }
 2809
 2810    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2811        self.leader_id
 2812    }
 2813
 2814    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2815        &self.buffer
 2816    }
 2817
 2818    pub fn project(&self) -> Option<&Entity<Project>> {
 2819        self.project.as_ref()
 2820    }
 2821
 2822    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2823        self.workspace.as_ref()?.0.upgrade()
 2824    }
 2825
 2826    /// Returns the workspace serialization ID if this editor should be serialized.
 2827    fn workspace_serialization_id(&self, _cx: &App) -> Option<WorkspaceId> {
 2828        self.workspace
 2829            .as_ref()
 2830            .filter(|_| self.should_serialize_buffer())
 2831            .and_then(|workspace| workspace.1)
 2832    }
 2833
 2834    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2835        self.buffer().read(cx).title(cx)
 2836    }
 2837
 2838    pub fn snapshot(&self, window: &Window, cx: &mut App) -> EditorSnapshot {
 2839        let git_blame_gutter_max_author_length = self
 2840            .render_git_blame_gutter(cx)
 2841            .then(|| {
 2842                if let Some(blame) = self.blame.as_ref() {
 2843                    let max_author_length =
 2844                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2845                    Some(max_author_length)
 2846                } else {
 2847                    None
 2848                }
 2849            })
 2850            .flatten();
 2851
 2852        EditorSnapshot {
 2853            mode: self.mode.clone(),
 2854            show_gutter: self.show_gutter,
 2855            show_line_numbers: self.show_line_numbers,
 2856            show_git_diff_gutter: self.show_git_diff_gutter,
 2857            show_code_actions: self.show_code_actions,
 2858            show_runnables: self.show_runnables,
 2859            show_breakpoints: self.show_breakpoints,
 2860            git_blame_gutter_max_author_length,
 2861            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2862            placeholder_display_snapshot: self
 2863                .placeholder_display_map
 2864                .as_ref()
 2865                .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx))),
 2866            scroll_anchor: self.scroll_manager.anchor(),
 2867            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2868            is_focused: self.focus_handle.is_focused(window),
 2869            current_line_highlight: self
 2870                .current_line_highlight
 2871                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2872            gutter_hovered: self.gutter_hovered,
 2873        }
 2874    }
 2875
 2876    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2877        self.buffer.read(cx).language_at(point, cx)
 2878    }
 2879
 2880    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2881        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2882    }
 2883
 2884    pub fn active_excerpt(
 2885        &self,
 2886        cx: &App,
 2887    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2888        self.buffer
 2889            .read(cx)
 2890            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2891    }
 2892
 2893    pub fn mode(&self) -> &EditorMode {
 2894        &self.mode
 2895    }
 2896
 2897    pub fn set_mode(&mut self, mode: EditorMode) {
 2898        self.mode = mode;
 2899    }
 2900
 2901    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2902        self.collaboration_hub.as_deref()
 2903    }
 2904
 2905    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2906        self.collaboration_hub = Some(hub);
 2907    }
 2908
 2909    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2910        self.in_project_search = in_project_search;
 2911    }
 2912
 2913    pub fn set_custom_context_menu(
 2914        &mut self,
 2915        f: impl 'static
 2916        + Fn(
 2917            &mut Self,
 2918            DisplayPoint,
 2919            &mut Window,
 2920            &mut Context<Self>,
 2921        ) -> Option<Entity<ui::ContextMenu>>,
 2922    ) {
 2923        self.custom_context_menu = Some(Box::new(f))
 2924    }
 2925
 2926    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 2927        self.completion_provider = provider;
 2928    }
 2929
 2930    #[cfg(any(test, feature = "test-support"))]
 2931    pub fn completion_provider(&self) -> Option<Rc<dyn CompletionProvider>> {
 2932        self.completion_provider.clone()
 2933    }
 2934
 2935    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 2936        self.semantics_provider.clone()
 2937    }
 2938
 2939    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 2940        self.semantics_provider = provider;
 2941    }
 2942
 2943    pub fn set_edit_prediction_provider<T>(
 2944        &mut self,
 2945        provider: Option<Entity<T>>,
 2946        window: &mut Window,
 2947        cx: &mut Context<Self>,
 2948    ) where
 2949        T: EditPredictionProvider,
 2950    {
 2951        self.edit_prediction_provider = provider.map(|provider| RegisteredEditPredictionProvider {
 2952            _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 2953                if this.focus_handle.is_focused(window) {
 2954                    this.update_visible_edit_prediction(window, cx);
 2955                }
 2956            }),
 2957            provider: Arc::new(provider),
 2958        });
 2959        self.update_edit_prediction_settings(cx);
 2960        self.refresh_edit_prediction(false, false, window, cx);
 2961    }
 2962
 2963    pub fn placeholder_text(&self, cx: &mut App) -> Option<String> {
 2964        self.placeholder_display_map
 2965            .as_ref()
 2966            .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx)).text())
 2967    }
 2968
 2969    pub fn set_placeholder_text(
 2970        &mut self,
 2971        placeholder_text: &str,
 2972        window: &mut Window,
 2973        cx: &mut Context<Self>,
 2974    ) {
 2975        let multibuffer = cx
 2976            .new(|cx| MultiBuffer::singleton(cx.new(|cx| Buffer::local(placeholder_text, cx)), cx));
 2977
 2978        let style = window.text_style();
 2979
 2980        self.placeholder_display_map = Some(cx.new(|cx| {
 2981            DisplayMap::new(
 2982                multibuffer,
 2983                style.font(),
 2984                style.font_size.to_pixels(window.rem_size()),
 2985                None,
 2986                FILE_HEADER_HEIGHT,
 2987                MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 2988                Default::default(),
 2989                DiagnosticSeverity::Off,
 2990                cx,
 2991            )
 2992        }));
 2993        cx.notify();
 2994    }
 2995
 2996    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 2997        self.cursor_shape = cursor_shape;
 2998
 2999        // Disrupt blink for immediate user feedback that the cursor shape has changed
 3000        self.blink_manager.update(cx, BlinkManager::show_cursor);
 3001
 3002        cx.notify();
 3003    }
 3004
 3005    pub fn set_current_line_highlight(
 3006        &mut self,
 3007        current_line_highlight: Option<CurrentLineHighlight>,
 3008    ) {
 3009        self.current_line_highlight = current_line_highlight;
 3010    }
 3011
 3012    pub fn range_for_match<T: std::marker::Copy>(
 3013        &self,
 3014        range: &Range<T>,
 3015        collapse: bool,
 3016    ) -> Range<T> {
 3017        if collapse {
 3018            return range.start..range.start;
 3019        }
 3020        range.clone()
 3021    }
 3022
 3023    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 3024        if self.display_map.read(cx).clip_at_line_ends != clip {
 3025            self.display_map
 3026                .update(cx, |map, _| map.clip_at_line_ends = clip);
 3027        }
 3028    }
 3029
 3030    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 3031        self.input_enabled = input_enabled;
 3032    }
 3033
 3034    pub fn set_edit_predictions_hidden_for_vim_mode(
 3035        &mut self,
 3036        hidden: bool,
 3037        window: &mut Window,
 3038        cx: &mut Context<Self>,
 3039    ) {
 3040        if hidden != self.edit_predictions_hidden_for_vim_mode {
 3041            self.edit_predictions_hidden_for_vim_mode = hidden;
 3042            if hidden {
 3043                self.update_visible_edit_prediction(window, cx);
 3044            } else {
 3045                self.refresh_edit_prediction(true, false, window, cx);
 3046            }
 3047        }
 3048    }
 3049
 3050    pub fn set_menu_edit_predictions_policy(&mut self, value: MenuEditPredictionsPolicy) {
 3051        self.menu_edit_predictions_policy = value;
 3052    }
 3053
 3054    pub fn set_autoindent(&mut self, autoindent: bool) {
 3055        if autoindent {
 3056            self.autoindent_mode = Some(AutoindentMode::EachLine);
 3057        } else {
 3058            self.autoindent_mode = None;
 3059        }
 3060    }
 3061
 3062    pub fn read_only(&self, cx: &App) -> bool {
 3063        self.read_only || self.buffer.read(cx).read_only()
 3064    }
 3065
 3066    pub fn set_read_only(&mut self, read_only: bool) {
 3067        self.read_only = read_only;
 3068    }
 3069
 3070    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 3071        self.use_autoclose = autoclose;
 3072    }
 3073
 3074    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 3075        self.use_auto_surround = auto_surround;
 3076    }
 3077
 3078    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 3079        self.auto_replace_emoji_shortcode = auto_replace;
 3080    }
 3081
 3082    pub fn set_should_serialize(&mut self, should_serialize: bool, cx: &App) {
 3083        self.buffer_serialization = should_serialize.then(|| {
 3084            BufferSerialization::new(
 3085                ProjectSettings::get_global(cx)
 3086                    .session
 3087                    .restore_unsaved_buffers,
 3088            )
 3089        })
 3090    }
 3091
 3092    fn should_serialize_buffer(&self) -> bool {
 3093        self.buffer_serialization.is_some()
 3094    }
 3095
 3096    pub fn toggle_edit_predictions(
 3097        &mut self,
 3098        _: &ToggleEditPrediction,
 3099        window: &mut Window,
 3100        cx: &mut Context<Self>,
 3101    ) {
 3102        if self.show_edit_predictions_override.is_some() {
 3103            self.set_show_edit_predictions(None, window, cx);
 3104        } else {
 3105            let show_edit_predictions = !self.edit_predictions_enabled();
 3106            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 3107        }
 3108    }
 3109
 3110    pub fn set_show_edit_predictions(
 3111        &mut self,
 3112        show_edit_predictions: Option<bool>,
 3113        window: &mut Window,
 3114        cx: &mut Context<Self>,
 3115    ) {
 3116        self.show_edit_predictions_override = show_edit_predictions;
 3117        self.update_edit_prediction_settings(cx);
 3118
 3119        if let Some(false) = show_edit_predictions {
 3120            self.discard_edit_prediction(false, cx);
 3121        } else {
 3122            self.refresh_edit_prediction(false, true, window, cx);
 3123        }
 3124    }
 3125
 3126    fn edit_predictions_disabled_in_scope(
 3127        &self,
 3128        buffer: &Entity<Buffer>,
 3129        buffer_position: language::Anchor,
 3130        cx: &App,
 3131    ) -> bool {
 3132        let snapshot = buffer.read(cx).snapshot();
 3133        let settings = snapshot.settings_at(buffer_position, cx);
 3134
 3135        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 3136            return false;
 3137        };
 3138
 3139        scope.override_name().is_some_and(|scope_name| {
 3140            settings
 3141                .edit_predictions_disabled_in
 3142                .iter()
 3143                .any(|s| s == scope_name)
 3144        })
 3145    }
 3146
 3147    pub fn set_use_modal_editing(&mut self, to: bool) {
 3148        self.use_modal_editing = to;
 3149    }
 3150
 3151    pub fn use_modal_editing(&self) -> bool {
 3152        self.use_modal_editing
 3153    }
 3154
 3155    fn selections_did_change(
 3156        &mut self,
 3157        local: bool,
 3158        old_cursor_position: &Anchor,
 3159        effects: SelectionEffects,
 3160        window: &mut Window,
 3161        cx: &mut Context<Self>,
 3162    ) {
 3163        window.invalidate_character_coordinates();
 3164
 3165        // Copy selections to primary selection buffer
 3166        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 3167        if local {
 3168            let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
 3169            let buffer_handle = self.buffer.read(cx).read(cx);
 3170
 3171            let mut text = String::new();
 3172            for (index, selection) in selections.iter().enumerate() {
 3173                let text_for_selection = buffer_handle
 3174                    .text_for_range(selection.start..selection.end)
 3175                    .collect::<String>();
 3176
 3177                text.push_str(&text_for_selection);
 3178                if index != selections.len() - 1 {
 3179                    text.push('\n');
 3180                }
 3181            }
 3182
 3183            if !text.is_empty() {
 3184                cx.write_to_primary(ClipboardItem::new_string(text));
 3185            }
 3186        }
 3187
 3188        let selection_anchors = self.selections.disjoint_anchors_arc();
 3189
 3190        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 3191            self.buffer.update(cx, |buffer, cx| {
 3192                buffer.set_active_selections(
 3193                    &selection_anchors,
 3194                    self.selections.line_mode(),
 3195                    self.cursor_shape,
 3196                    cx,
 3197                )
 3198            });
 3199        }
 3200        let display_map = self
 3201            .display_map
 3202            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3203        let buffer = display_map.buffer_snapshot();
 3204        if self.selections.count() == 1 {
 3205            self.add_selections_state = None;
 3206        }
 3207        self.select_next_state = None;
 3208        self.select_prev_state = None;
 3209        self.select_syntax_node_history.try_clear();
 3210        self.invalidate_autoclose_regions(&selection_anchors, buffer);
 3211        self.snippet_stack.invalidate(&selection_anchors, buffer);
 3212        self.take_rename(false, window, cx);
 3213
 3214        let newest_selection = self.selections.newest_anchor();
 3215        let new_cursor_position = newest_selection.head();
 3216        let selection_start = newest_selection.start;
 3217
 3218        if effects.nav_history.is_none() || effects.nav_history == Some(true) {
 3219            self.push_to_nav_history(
 3220                *old_cursor_position,
 3221                Some(new_cursor_position.to_point(buffer)),
 3222                false,
 3223                effects.nav_history == Some(true),
 3224                cx,
 3225            );
 3226        }
 3227
 3228        if local {
 3229            if let Some(buffer_id) = new_cursor_position.buffer_id {
 3230                self.register_buffer(buffer_id, cx);
 3231            }
 3232
 3233            let mut context_menu = self.context_menu.borrow_mut();
 3234            let completion_menu = match context_menu.as_ref() {
 3235                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 3236                Some(CodeContextMenu::CodeActions(_)) => {
 3237                    *context_menu = None;
 3238                    None
 3239                }
 3240                None => None,
 3241            };
 3242            let completion_position = completion_menu.map(|menu| menu.initial_position);
 3243            drop(context_menu);
 3244
 3245            if effects.completions
 3246                && let Some(completion_position) = completion_position
 3247            {
 3248                let start_offset = selection_start.to_offset(buffer);
 3249                let position_matches = start_offset == completion_position.to_offset(buffer);
 3250                let continue_showing = if position_matches {
 3251                    if self.snippet_stack.is_empty() {
 3252                        buffer.char_kind_before(start_offset, Some(CharScopeContext::Completion))
 3253                            == Some(CharKind::Word)
 3254                    } else {
 3255                        // Snippet choices can be shown even when the cursor is in whitespace.
 3256                        // Dismissing the menu with actions like backspace is handled by
 3257                        // invalidation regions.
 3258                        true
 3259                    }
 3260                } else {
 3261                    false
 3262                };
 3263
 3264                if continue_showing {
 3265                    self.open_or_update_completions_menu(None, None, false, window, cx);
 3266                } else {
 3267                    self.hide_context_menu(window, cx);
 3268                }
 3269            }
 3270
 3271            hide_hover(self, cx);
 3272
 3273            if old_cursor_position.to_display_point(&display_map).row()
 3274                != new_cursor_position.to_display_point(&display_map).row()
 3275            {
 3276                self.available_code_actions.take();
 3277            }
 3278            self.refresh_code_actions(window, cx);
 3279            self.refresh_document_highlights(cx);
 3280            refresh_linked_ranges(self, window, cx);
 3281
 3282            self.refresh_selected_text_highlights(false, window, cx);
 3283            self.refresh_matching_bracket_highlights(window, cx);
 3284            self.update_visible_edit_prediction(window, cx);
 3285            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 3286            self.inline_blame_popover.take();
 3287            if self.git_blame_inline_enabled {
 3288                self.start_inline_blame_timer(window, cx);
 3289            }
 3290        }
 3291
 3292        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 3293        cx.emit(EditorEvent::SelectionsChanged { local });
 3294
 3295        let selections = &self.selections.disjoint_anchors_arc();
 3296        if selections.len() == 1 {
 3297            cx.emit(SearchEvent::ActiveMatchChanged)
 3298        }
 3299        if local && let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 3300            let inmemory_selections = selections
 3301                .iter()
 3302                .map(|s| {
 3303                    text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 3304                        ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 3305                })
 3306                .collect();
 3307            self.update_restoration_data(cx, |data| {
 3308                data.selections = inmemory_selections;
 3309            });
 3310
 3311            if WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
 3312                && let Some(workspace_id) = self.workspace_serialization_id(cx)
 3313            {
 3314                let snapshot = self.buffer().read(cx).snapshot(cx);
 3315                let selections = selections.clone();
 3316                let background_executor = cx.background_executor().clone();
 3317                let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3318                self.serialize_selections = cx.background_spawn(async move {
 3319                    background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3320                    let db_selections = selections
 3321                        .iter()
 3322                        .map(|selection| {
 3323                            (
 3324                                selection.start.to_offset(&snapshot),
 3325                                selection.end.to_offset(&snapshot),
 3326                            )
 3327                        })
 3328                        .collect();
 3329
 3330                    DB.save_editor_selections(editor_id, workspace_id, db_selections)
 3331                        .await
 3332                        .with_context(|| {
 3333                            format!(
 3334                                "persisting editor selections for editor {editor_id}, \
 3335                                workspace {workspace_id:?}"
 3336                            )
 3337                        })
 3338                        .log_err();
 3339                });
 3340            }
 3341        }
 3342
 3343        cx.notify();
 3344    }
 3345
 3346    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 3347        use text::ToOffset as _;
 3348        use text::ToPoint as _;
 3349
 3350        if self.mode.is_minimap()
 3351            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 3352        {
 3353            return;
 3354        }
 3355
 3356        if !self.buffer().read(cx).is_singleton() {
 3357            return;
 3358        }
 3359
 3360        let display_snapshot = self
 3361            .display_map
 3362            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3363        let Some((.., snapshot)) = display_snapshot.buffer_snapshot().as_singleton() else {
 3364            return;
 3365        };
 3366        let inmemory_folds = display_snapshot
 3367            .folds_in_range(0..display_snapshot.buffer_snapshot().len())
 3368            .map(|fold| {
 3369                fold.range.start.text_anchor.to_point(&snapshot)
 3370                    ..fold.range.end.text_anchor.to_point(&snapshot)
 3371            })
 3372            .collect();
 3373        self.update_restoration_data(cx, |data| {
 3374            data.folds = inmemory_folds;
 3375        });
 3376
 3377        let Some(workspace_id) = self.workspace_serialization_id(cx) else {
 3378            return;
 3379        };
 3380        let background_executor = cx.background_executor().clone();
 3381        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3382        let db_folds = display_snapshot
 3383            .folds_in_range(0..display_snapshot.buffer_snapshot().len())
 3384            .map(|fold| {
 3385                (
 3386                    fold.range.start.text_anchor.to_offset(&snapshot),
 3387                    fold.range.end.text_anchor.to_offset(&snapshot),
 3388                )
 3389            })
 3390            .collect();
 3391        self.serialize_folds = cx.background_spawn(async move {
 3392            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3393            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 3394                .await
 3395                .with_context(|| {
 3396                    format!(
 3397                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 3398                    )
 3399                })
 3400                .log_err();
 3401        });
 3402    }
 3403
 3404    pub fn sync_selections(
 3405        &mut self,
 3406        other: Entity<Editor>,
 3407        cx: &mut Context<Self>,
 3408    ) -> gpui::Subscription {
 3409        let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3410        if !other_selections.is_empty() {
 3411            self.selections
 3412                .change_with(&self.display_snapshot(cx), |selections| {
 3413                    selections.select_anchors(other_selections);
 3414                });
 3415        }
 3416
 3417        let other_subscription = cx.subscribe(&other, |this, other, other_evt, cx| {
 3418            if let EditorEvent::SelectionsChanged { local: true } = other_evt {
 3419                let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3420                if other_selections.is_empty() {
 3421                    return;
 3422                }
 3423                let snapshot = this.display_snapshot(cx);
 3424                this.selections.change_with(&snapshot, |selections| {
 3425                    selections.select_anchors(other_selections);
 3426                });
 3427            }
 3428        });
 3429
 3430        let this_subscription = cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| {
 3431            if let EditorEvent::SelectionsChanged { local: true } = this_evt {
 3432                let these_selections = this.selections.disjoint_anchors().to_vec();
 3433                if these_selections.is_empty() {
 3434                    return;
 3435                }
 3436                other.update(cx, |other_editor, cx| {
 3437                    let snapshot = other_editor.display_snapshot(cx);
 3438                    other_editor
 3439                        .selections
 3440                        .change_with(&snapshot, |selections| {
 3441                            selections.select_anchors(these_selections);
 3442                        })
 3443                });
 3444            }
 3445        });
 3446
 3447        Subscription::join(other_subscription, this_subscription)
 3448    }
 3449
 3450    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 3451    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 3452    /// effects of selection change occur at the end of the transaction.
 3453    pub fn change_selections<R>(
 3454        &mut self,
 3455        effects: SelectionEffects,
 3456        window: &mut Window,
 3457        cx: &mut Context<Self>,
 3458        change: impl FnOnce(&mut MutableSelectionsCollection<'_, '_>) -> R,
 3459    ) -> R {
 3460        let snapshot = self.display_snapshot(cx);
 3461        if let Some(state) = &mut self.deferred_selection_effects_state {
 3462            state.effects.scroll = effects.scroll.or(state.effects.scroll);
 3463            state.effects.completions = effects.completions;
 3464            state.effects.nav_history = effects.nav_history.or(state.effects.nav_history);
 3465            let (changed, result) = self.selections.change_with(&snapshot, change);
 3466            state.changed |= changed;
 3467            return result;
 3468        }
 3469        let mut state = DeferredSelectionEffectsState {
 3470            changed: false,
 3471            effects,
 3472            old_cursor_position: self.selections.newest_anchor().head(),
 3473            history_entry: SelectionHistoryEntry {
 3474                selections: self.selections.disjoint_anchors_arc(),
 3475                select_next_state: self.select_next_state.clone(),
 3476                select_prev_state: self.select_prev_state.clone(),
 3477                add_selections_state: self.add_selections_state.clone(),
 3478            },
 3479        };
 3480        let (changed, result) = self.selections.change_with(&snapshot, change);
 3481        state.changed = state.changed || changed;
 3482        if self.defer_selection_effects {
 3483            self.deferred_selection_effects_state = Some(state);
 3484        } else {
 3485            self.apply_selection_effects(state, window, cx);
 3486        }
 3487        result
 3488    }
 3489
 3490    /// Defers the effects of selection change, so that the effects of multiple calls to
 3491    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3492    /// to selection history and the state of popovers based on selection position aren't
 3493    /// erroneously updated.
 3494    pub fn with_selection_effects_deferred<R>(
 3495        &mut self,
 3496        window: &mut Window,
 3497        cx: &mut Context<Self>,
 3498        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3499    ) -> R {
 3500        let already_deferred = self.defer_selection_effects;
 3501        self.defer_selection_effects = true;
 3502        let result = update(self, window, cx);
 3503        if !already_deferred {
 3504            self.defer_selection_effects = false;
 3505            if let Some(state) = self.deferred_selection_effects_state.take() {
 3506                self.apply_selection_effects(state, window, cx);
 3507            }
 3508        }
 3509        result
 3510    }
 3511
 3512    fn apply_selection_effects(
 3513        &mut self,
 3514        state: DeferredSelectionEffectsState,
 3515        window: &mut Window,
 3516        cx: &mut Context<Self>,
 3517    ) {
 3518        if state.changed {
 3519            self.selection_history.push(state.history_entry);
 3520
 3521            if let Some(autoscroll) = state.effects.scroll {
 3522                self.request_autoscroll(autoscroll, cx);
 3523            }
 3524
 3525            let old_cursor_position = &state.old_cursor_position;
 3526
 3527            self.selections_did_change(true, old_cursor_position, state.effects, window, cx);
 3528
 3529            if self.should_open_signature_help_automatically(old_cursor_position, cx) {
 3530                self.show_signature_help(&ShowSignatureHelp, window, cx);
 3531            }
 3532        }
 3533    }
 3534
 3535    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3536    where
 3537        I: IntoIterator<Item = (Range<S>, T)>,
 3538        S: ToOffset,
 3539        T: Into<Arc<str>>,
 3540    {
 3541        if self.read_only(cx) {
 3542            return;
 3543        }
 3544
 3545        self.buffer
 3546            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3547    }
 3548
 3549    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3550    where
 3551        I: IntoIterator<Item = (Range<S>, T)>,
 3552        S: ToOffset,
 3553        T: Into<Arc<str>>,
 3554    {
 3555        if self.read_only(cx) {
 3556            return;
 3557        }
 3558
 3559        self.buffer.update(cx, |buffer, cx| {
 3560            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3561        });
 3562    }
 3563
 3564    pub fn edit_with_block_indent<I, S, T>(
 3565        &mut self,
 3566        edits: I,
 3567        original_indent_columns: Vec<Option<u32>>,
 3568        cx: &mut Context<Self>,
 3569    ) where
 3570        I: IntoIterator<Item = (Range<S>, T)>,
 3571        S: ToOffset,
 3572        T: Into<Arc<str>>,
 3573    {
 3574        if self.read_only(cx) {
 3575            return;
 3576        }
 3577
 3578        self.buffer.update(cx, |buffer, cx| {
 3579            buffer.edit(
 3580                edits,
 3581                Some(AutoindentMode::Block {
 3582                    original_indent_columns,
 3583                }),
 3584                cx,
 3585            )
 3586        });
 3587    }
 3588
 3589    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3590        self.hide_context_menu(window, cx);
 3591
 3592        match phase {
 3593            SelectPhase::Begin {
 3594                position,
 3595                add,
 3596                click_count,
 3597            } => self.begin_selection(position, add, click_count, window, cx),
 3598            SelectPhase::BeginColumnar {
 3599                position,
 3600                goal_column,
 3601                reset,
 3602                mode,
 3603            } => self.begin_columnar_selection(position, goal_column, reset, mode, window, cx),
 3604            SelectPhase::Extend {
 3605                position,
 3606                click_count,
 3607            } => self.extend_selection(position, click_count, window, cx),
 3608            SelectPhase::Update {
 3609                position,
 3610                goal_column,
 3611                scroll_delta,
 3612            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3613            SelectPhase::End => self.end_selection(window, cx),
 3614        }
 3615    }
 3616
 3617    fn extend_selection(
 3618        &mut self,
 3619        position: DisplayPoint,
 3620        click_count: usize,
 3621        window: &mut Window,
 3622        cx: &mut Context<Self>,
 3623    ) {
 3624        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3625        let tail = self.selections.newest::<usize>(&display_map).tail();
 3626        let click_count = click_count.max(match self.selections.select_mode() {
 3627            SelectMode::Character => 1,
 3628            SelectMode::Word(_) => 2,
 3629            SelectMode::Line(_) => 3,
 3630            SelectMode::All => 4,
 3631        });
 3632        self.begin_selection(position, false, click_count, window, cx);
 3633
 3634        let tail_anchor = display_map.buffer_snapshot().anchor_before(tail);
 3635
 3636        let current_selection = match self.selections.select_mode() {
 3637            SelectMode::Character | SelectMode::All => tail_anchor..tail_anchor,
 3638            SelectMode::Word(range) | SelectMode::Line(range) => range.clone(),
 3639        };
 3640
 3641        let mut pending_selection = self
 3642            .selections
 3643            .pending_anchor()
 3644            .cloned()
 3645            .expect("extend_selection not called with pending selection");
 3646
 3647        if pending_selection
 3648            .start
 3649            .cmp(&current_selection.start, display_map.buffer_snapshot())
 3650            == Ordering::Greater
 3651        {
 3652            pending_selection.start = current_selection.start;
 3653        }
 3654        if pending_selection
 3655            .end
 3656            .cmp(&current_selection.end, display_map.buffer_snapshot())
 3657            == Ordering::Less
 3658        {
 3659            pending_selection.end = current_selection.end;
 3660            pending_selection.reversed = true;
 3661        }
 3662
 3663        let mut pending_mode = self.selections.pending_mode().unwrap();
 3664        match &mut pending_mode {
 3665            SelectMode::Word(range) | SelectMode::Line(range) => *range = current_selection,
 3666            _ => {}
 3667        }
 3668
 3669        let effects = if EditorSettings::get_global(cx).autoscroll_on_clicks {
 3670            SelectionEffects::scroll(Autoscroll::fit())
 3671        } else {
 3672            SelectionEffects::no_scroll()
 3673        };
 3674
 3675        self.change_selections(effects, window, cx, |s| {
 3676            s.set_pending(pending_selection.clone(), pending_mode);
 3677            s.set_is_extending(true);
 3678        });
 3679    }
 3680
 3681    fn begin_selection(
 3682        &mut self,
 3683        position: DisplayPoint,
 3684        add: bool,
 3685        click_count: usize,
 3686        window: &mut Window,
 3687        cx: &mut Context<Self>,
 3688    ) {
 3689        if !self.focus_handle.is_focused(window) {
 3690            self.last_focused_descendant = None;
 3691            window.focus(&self.focus_handle);
 3692        }
 3693
 3694        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3695        let buffer = display_map.buffer_snapshot();
 3696        let position = display_map.clip_point(position, Bias::Left);
 3697
 3698        let start;
 3699        let end;
 3700        let mode;
 3701        let mut auto_scroll;
 3702        match click_count {
 3703            1 => {
 3704                start = buffer.anchor_before(position.to_point(&display_map));
 3705                end = start;
 3706                mode = SelectMode::Character;
 3707                auto_scroll = true;
 3708            }
 3709            2 => {
 3710                let position = display_map
 3711                    .clip_point(position, Bias::Left)
 3712                    .to_offset(&display_map, Bias::Left);
 3713                let (range, _) = buffer.surrounding_word(position, None);
 3714                start = buffer.anchor_before(range.start);
 3715                end = buffer.anchor_before(range.end);
 3716                mode = SelectMode::Word(start..end);
 3717                auto_scroll = true;
 3718            }
 3719            3 => {
 3720                let position = display_map
 3721                    .clip_point(position, Bias::Left)
 3722                    .to_point(&display_map);
 3723                let line_start = display_map.prev_line_boundary(position).0;
 3724                let next_line_start = buffer.clip_point(
 3725                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3726                    Bias::Left,
 3727                );
 3728                start = buffer.anchor_before(line_start);
 3729                end = buffer.anchor_before(next_line_start);
 3730                mode = SelectMode::Line(start..end);
 3731                auto_scroll = true;
 3732            }
 3733            _ => {
 3734                start = buffer.anchor_before(0);
 3735                end = buffer.anchor_before(buffer.len());
 3736                mode = SelectMode::All;
 3737                auto_scroll = false;
 3738            }
 3739        }
 3740        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3741
 3742        let point_to_delete: Option<usize> = {
 3743            let selected_points: Vec<Selection<Point>> =
 3744                self.selections.disjoint_in_range(start..end, &display_map);
 3745
 3746            if !add || click_count > 1 {
 3747                None
 3748            } else if !selected_points.is_empty() {
 3749                Some(selected_points[0].id)
 3750            } else {
 3751                let clicked_point_already_selected =
 3752                    self.selections.disjoint_anchors().iter().find(|selection| {
 3753                        selection.start.to_point(buffer) == start.to_point(buffer)
 3754                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3755                    });
 3756
 3757                clicked_point_already_selected.map(|selection| selection.id)
 3758            }
 3759        };
 3760
 3761        let selections_count = self.selections.count();
 3762        let effects = if auto_scroll {
 3763            SelectionEffects::default()
 3764        } else {
 3765            SelectionEffects::no_scroll()
 3766        };
 3767
 3768        self.change_selections(effects, window, cx, |s| {
 3769            if let Some(point_to_delete) = point_to_delete {
 3770                s.delete(point_to_delete);
 3771
 3772                if selections_count == 1 {
 3773                    s.set_pending_anchor_range(start..end, mode);
 3774                }
 3775            } else {
 3776                if !add {
 3777                    s.clear_disjoint();
 3778                }
 3779
 3780                s.set_pending_anchor_range(start..end, mode);
 3781            }
 3782        });
 3783    }
 3784
 3785    fn begin_columnar_selection(
 3786        &mut self,
 3787        position: DisplayPoint,
 3788        goal_column: u32,
 3789        reset: bool,
 3790        mode: ColumnarMode,
 3791        window: &mut Window,
 3792        cx: &mut Context<Self>,
 3793    ) {
 3794        if !self.focus_handle.is_focused(window) {
 3795            self.last_focused_descendant = None;
 3796            window.focus(&self.focus_handle);
 3797        }
 3798
 3799        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3800
 3801        if reset {
 3802            let pointer_position = display_map
 3803                .buffer_snapshot()
 3804                .anchor_before(position.to_point(&display_map));
 3805
 3806            self.change_selections(
 3807                SelectionEffects::scroll(Autoscroll::newest()),
 3808                window,
 3809                cx,
 3810                |s| {
 3811                    s.clear_disjoint();
 3812                    s.set_pending_anchor_range(
 3813                        pointer_position..pointer_position,
 3814                        SelectMode::Character,
 3815                    );
 3816                },
 3817            );
 3818        };
 3819
 3820        let tail = self.selections.newest::<Point>(&display_map).tail();
 3821        let selection_anchor = display_map.buffer_snapshot().anchor_before(tail);
 3822        self.columnar_selection_state = match mode {
 3823            ColumnarMode::FromMouse => Some(ColumnarSelectionState::FromMouse {
 3824                selection_tail: selection_anchor,
 3825                display_point: if reset {
 3826                    if position.column() != goal_column {
 3827                        Some(DisplayPoint::new(position.row(), goal_column))
 3828                    } else {
 3829                        None
 3830                    }
 3831                } else {
 3832                    None
 3833                },
 3834            }),
 3835            ColumnarMode::FromSelection => Some(ColumnarSelectionState::FromSelection {
 3836                selection_tail: selection_anchor,
 3837            }),
 3838        };
 3839
 3840        if !reset {
 3841            self.select_columns(position, goal_column, &display_map, window, cx);
 3842        }
 3843    }
 3844
 3845    fn update_selection(
 3846        &mut self,
 3847        position: DisplayPoint,
 3848        goal_column: u32,
 3849        scroll_delta: gpui::Point<f32>,
 3850        window: &mut Window,
 3851        cx: &mut Context<Self>,
 3852    ) {
 3853        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3854
 3855        if self.columnar_selection_state.is_some() {
 3856            self.select_columns(position, goal_column, &display_map, window, cx);
 3857        } else if let Some(mut pending) = self.selections.pending_anchor().cloned() {
 3858            let buffer = display_map.buffer_snapshot();
 3859            let head;
 3860            let tail;
 3861            let mode = self.selections.pending_mode().unwrap();
 3862            match &mode {
 3863                SelectMode::Character => {
 3864                    head = position.to_point(&display_map);
 3865                    tail = pending.tail().to_point(buffer);
 3866                }
 3867                SelectMode::Word(original_range) => {
 3868                    let offset = display_map
 3869                        .clip_point(position, Bias::Left)
 3870                        .to_offset(&display_map, Bias::Left);
 3871                    let original_range = original_range.to_offset(buffer);
 3872
 3873                    let head_offset = if buffer.is_inside_word(offset, None)
 3874                        || original_range.contains(&offset)
 3875                    {
 3876                        let (word_range, _) = buffer.surrounding_word(offset, None);
 3877                        if word_range.start < original_range.start {
 3878                            word_range.start
 3879                        } else {
 3880                            word_range.end
 3881                        }
 3882                    } else {
 3883                        offset
 3884                    };
 3885
 3886                    head = head_offset.to_point(buffer);
 3887                    if head_offset <= original_range.start {
 3888                        tail = original_range.end.to_point(buffer);
 3889                    } else {
 3890                        tail = original_range.start.to_point(buffer);
 3891                    }
 3892                }
 3893                SelectMode::Line(original_range) => {
 3894                    let original_range = original_range.to_point(display_map.buffer_snapshot());
 3895
 3896                    let position = display_map
 3897                        .clip_point(position, Bias::Left)
 3898                        .to_point(&display_map);
 3899                    let line_start = display_map.prev_line_boundary(position).0;
 3900                    let next_line_start = buffer.clip_point(
 3901                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3902                        Bias::Left,
 3903                    );
 3904
 3905                    if line_start < original_range.start {
 3906                        head = line_start
 3907                    } else {
 3908                        head = next_line_start
 3909                    }
 3910
 3911                    if head <= original_range.start {
 3912                        tail = original_range.end;
 3913                    } else {
 3914                        tail = original_range.start;
 3915                    }
 3916                }
 3917                SelectMode::All => {
 3918                    return;
 3919                }
 3920            };
 3921
 3922            if head < tail {
 3923                pending.start = buffer.anchor_before(head);
 3924                pending.end = buffer.anchor_before(tail);
 3925                pending.reversed = true;
 3926            } else {
 3927                pending.start = buffer.anchor_before(tail);
 3928                pending.end = buffer.anchor_before(head);
 3929                pending.reversed = false;
 3930            }
 3931
 3932            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3933                s.set_pending(pending.clone(), mode);
 3934            });
 3935        } else {
 3936            log::error!("update_selection dispatched with no pending selection");
 3937            return;
 3938        }
 3939
 3940        self.apply_scroll_delta(scroll_delta, window, cx);
 3941        cx.notify();
 3942    }
 3943
 3944    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3945        self.columnar_selection_state.take();
 3946        if let Some(pending_mode) = self.selections.pending_mode() {
 3947            let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
 3948            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3949                s.select(selections);
 3950                s.clear_pending();
 3951                if s.is_extending() {
 3952                    s.set_is_extending(false);
 3953                } else {
 3954                    s.set_select_mode(pending_mode);
 3955                }
 3956            });
 3957        }
 3958    }
 3959
 3960    fn select_columns(
 3961        &mut self,
 3962        head: DisplayPoint,
 3963        goal_column: u32,
 3964        display_map: &DisplaySnapshot,
 3965        window: &mut Window,
 3966        cx: &mut Context<Self>,
 3967    ) {
 3968        let Some(columnar_state) = self.columnar_selection_state.as_ref() else {
 3969            return;
 3970        };
 3971
 3972        let tail = match columnar_state {
 3973            ColumnarSelectionState::FromMouse {
 3974                selection_tail,
 3975                display_point,
 3976            } => display_point.unwrap_or_else(|| selection_tail.to_display_point(display_map)),
 3977            ColumnarSelectionState::FromSelection { selection_tail } => {
 3978                selection_tail.to_display_point(display_map)
 3979            }
 3980        };
 3981
 3982        let start_row = cmp::min(tail.row(), head.row());
 3983        let end_row = cmp::max(tail.row(), head.row());
 3984        let start_column = cmp::min(tail.column(), goal_column);
 3985        let end_column = cmp::max(tail.column(), goal_column);
 3986        let reversed = start_column < tail.column();
 3987
 3988        let selection_ranges = (start_row.0..=end_row.0)
 3989            .map(DisplayRow)
 3990            .filter_map(|row| {
 3991                if (matches!(columnar_state, ColumnarSelectionState::FromMouse { .. })
 3992                    || start_column <= display_map.line_len(row))
 3993                    && !display_map.is_block_line(row)
 3994                {
 3995                    let start = display_map
 3996                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 3997                        .to_point(display_map);
 3998                    let end = display_map
 3999                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 4000                        .to_point(display_map);
 4001                    if reversed {
 4002                        Some(end..start)
 4003                    } else {
 4004                        Some(start..end)
 4005                    }
 4006                } else {
 4007                    None
 4008                }
 4009            })
 4010            .collect::<Vec<_>>();
 4011        if selection_ranges.is_empty() {
 4012            return;
 4013        }
 4014
 4015        let ranges = match columnar_state {
 4016            ColumnarSelectionState::FromMouse { .. } => {
 4017                let mut non_empty_ranges = selection_ranges
 4018                    .iter()
 4019                    .filter(|selection_range| selection_range.start != selection_range.end)
 4020                    .peekable();
 4021                if non_empty_ranges.peek().is_some() {
 4022                    non_empty_ranges.cloned().collect()
 4023                } else {
 4024                    selection_ranges
 4025                }
 4026            }
 4027            _ => selection_ranges,
 4028        };
 4029
 4030        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 4031            s.select_ranges(ranges);
 4032        });
 4033        cx.notify();
 4034    }
 4035
 4036    pub fn has_non_empty_selection(&self, snapshot: &DisplaySnapshot) -> bool {
 4037        self.selections
 4038            .all_adjusted(snapshot)
 4039            .iter()
 4040            .any(|selection| !selection.is_empty())
 4041    }
 4042
 4043    pub fn has_pending_nonempty_selection(&self) -> bool {
 4044        let pending_nonempty_selection = match self.selections.pending_anchor() {
 4045            Some(Selection { start, end, .. }) => start != end,
 4046            None => false,
 4047        };
 4048
 4049        pending_nonempty_selection
 4050            || (self.columnar_selection_state.is_some()
 4051                && self.selections.disjoint_anchors().len() > 1)
 4052    }
 4053
 4054    pub fn has_pending_selection(&self) -> bool {
 4055        self.selections.pending_anchor().is_some() || self.columnar_selection_state.is_some()
 4056    }
 4057
 4058    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 4059        self.selection_mark_mode = false;
 4060        self.selection_drag_state = SelectionDragState::None;
 4061
 4062        if self.clear_expanded_diff_hunks(cx) {
 4063            cx.notify();
 4064            return;
 4065        }
 4066        if self.dismiss_menus_and_popups(true, window, cx) {
 4067            return;
 4068        }
 4069
 4070        if self.mode.is_full()
 4071            && self.change_selections(Default::default(), window, cx, |s| s.try_cancel())
 4072        {
 4073            return;
 4074        }
 4075
 4076        cx.propagate();
 4077    }
 4078
 4079    pub fn dismiss_menus_and_popups(
 4080        &mut self,
 4081        is_user_requested: bool,
 4082        window: &mut Window,
 4083        cx: &mut Context<Self>,
 4084    ) -> bool {
 4085        if self.take_rename(false, window, cx).is_some() {
 4086            return true;
 4087        }
 4088
 4089        if self.hide_blame_popover(true, cx) {
 4090            return true;
 4091        }
 4092
 4093        if hide_hover(self, cx) {
 4094            return true;
 4095        }
 4096
 4097        if self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape) {
 4098            return true;
 4099        }
 4100
 4101        if self.hide_context_menu(window, cx).is_some() {
 4102            return true;
 4103        }
 4104
 4105        if self.mouse_context_menu.take().is_some() {
 4106            return true;
 4107        }
 4108
 4109        if is_user_requested && self.discard_edit_prediction(true, cx) {
 4110            return true;
 4111        }
 4112
 4113        if self.snippet_stack.pop().is_some() {
 4114            return true;
 4115        }
 4116
 4117        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 4118            self.dismiss_diagnostics(cx);
 4119            return true;
 4120        }
 4121
 4122        false
 4123    }
 4124
 4125    fn linked_editing_ranges_for(
 4126        &self,
 4127        selection: Range<text::Anchor>,
 4128        cx: &App,
 4129    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 4130        if self.linked_edit_ranges.is_empty() {
 4131            return None;
 4132        }
 4133        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 4134            selection.end.buffer_id.and_then(|end_buffer_id| {
 4135                if selection.start.buffer_id != Some(end_buffer_id) {
 4136                    return None;
 4137                }
 4138                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 4139                let snapshot = buffer.read(cx).snapshot();
 4140                self.linked_edit_ranges
 4141                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 4142                    .map(|ranges| (ranges, snapshot, buffer))
 4143            })?;
 4144        use text::ToOffset as TO;
 4145        // find offset from the start of current range to current cursor position
 4146        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 4147
 4148        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 4149        let start_difference = start_offset - start_byte_offset;
 4150        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 4151        let end_difference = end_offset - start_byte_offset;
 4152        // Current range has associated linked ranges.
 4153        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4154        for range in linked_ranges.iter() {
 4155            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 4156            let end_offset = start_offset + end_difference;
 4157            let start_offset = start_offset + start_difference;
 4158            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 4159                continue;
 4160            }
 4161            if self.selections.disjoint_anchor_ranges().any(|s| {
 4162                if s.start.buffer_id != selection.start.buffer_id
 4163                    || s.end.buffer_id != selection.end.buffer_id
 4164                {
 4165                    return false;
 4166                }
 4167                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 4168                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 4169            }) {
 4170                continue;
 4171            }
 4172            let start = buffer_snapshot.anchor_after(start_offset);
 4173            let end = buffer_snapshot.anchor_after(end_offset);
 4174            linked_edits
 4175                .entry(buffer.clone())
 4176                .or_default()
 4177                .push(start..end);
 4178        }
 4179        Some(linked_edits)
 4180    }
 4181
 4182    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4183        let text: Arc<str> = text.into();
 4184
 4185        if self.read_only(cx) {
 4186            return;
 4187        }
 4188
 4189        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4190
 4191        let selections = self.selections.all_adjusted(&self.display_snapshot(cx));
 4192        let mut bracket_inserted = false;
 4193        let mut edits = Vec::new();
 4194        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4195        let mut new_selections = Vec::with_capacity(selections.len());
 4196        let mut new_autoclose_regions = Vec::new();
 4197        let snapshot = self.buffer.read(cx).read(cx);
 4198        let mut clear_linked_edit_ranges = false;
 4199
 4200        for (selection, autoclose_region) in
 4201            self.selections_with_autoclose_regions(selections, &snapshot)
 4202        {
 4203            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 4204                // Determine if the inserted text matches the opening or closing
 4205                // bracket of any of this language's bracket pairs.
 4206                let mut bracket_pair = None;
 4207                let mut is_bracket_pair_start = false;
 4208                let mut is_bracket_pair_end = false;
 4209                if !text.is_empty() {
 4210                    let mut bracket_pair_matching_end = None;
 4211                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 4212                    //  and they are removing the character that triggered IME popup.
 4213                    for (pair, enabled) in scope.brackets() {
 4214                        if !pair.close && !pair.surround {
 4215                            continue;
 4216                        }
 4217
 4218                        if enabled && pair.start.ends_with(text.as_ref()) {
 4219                            let prefix_len = pair.start.len() - text.len();
 4220                            let preceding_text_matches_prefix = prefix_len == 0
 4221                                || (selection.start.column >= (prefix_len as u32)
 4222                                    && snapshot.contains_str_at(
 4223                                        Point::new(
 4224                                            selection.start.row,
 4225                                            selection.start.column - (prefix_len as u32),
 4226                                        ),
 4227                                        &pair.start[..prefix_len],
 4228                                    ));
 4229                            if preceding_text_matches_prefix {
 4230                                bracket_pair = Some(pair.clone());
 4231                                is_bracket_pair_start = true;
 4232                                break;
 4233                            }
 4234                        }
 4235                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 4236                        {
 4237                            // take first bracket pair matching end, but don't break in case a later bracket
 4238                            // pair matches start
 4239                            bracket_pair_matching_end = Some(pair.clone());
 4240                        }
 4241                    }
 4242                    if let Some(end) = bracket_pair_matching_end
 4243                        && bracket_pair.is_none()
 4244                    {
 4245                        bracket_pair = Some(end);
 4246                        is_bracket_pair_end = true;
 4247                    }
 4248                }
 4249
 4250                if let Some(bracket_pair) = bracket_pair {
 4251                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 4252                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 4253                    let auto_surround =
 4254                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 4255                    if selection.is_empty() {
 4256                        if is_bracket_pair_start {
 4257                            // If the inserted text is a suffix of an opening bracket and the
 4258                            // selection is preceded by the rest of the opening bracket, then
 4259                            // insert the closing bracket.
 4260                            let following_text_allows_autoclose = snapshot
 4261                                .chars_at(selection.start)
 4262                                .next()
 4263                                .is_none_or(|c| scope.should_autoclose_before(c));
 4264
 4265                            let preceding_text_allows_autoclose = selection.start.column == 0
 4266                                || snapshot
 4267                                    .reversed_chars_at(selection.start)
 4268                                    .next()
 4269                                    .is_none_or(|c| {
 4270                                        bracket_pair.start != bracket_pair.end
 4271                                            || !snapshot
 4272                                                .char_classifier_at(selection.start)
 4273                                                .is_word(c)
 4274                                    });
 4275
 4276                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 4277                                && bracket_pair.start.len() == 1
 4278                            {
 4279                                let target = bracket_pair.start.chars().next().unwrap();
 4280                                let current_line_count = snapshot
 4281                                    .reversed_chars_at(selection.start)
 4282                                    .take_while(|&c| c != '\n')
 4283                                    .filter(|&c| c == target)
 4284                                    .count();
 4285                                current_line_count % 2 == 1
 4286                            } else {
 4287                                false
 4288                            };
 4289
 4290                            if autoclose
 4291                                && bracket_pair.close
 4292                                && following_text_allows_autoclose
 4293                                && preceding_text_allows_autoclose
 4294                                && !is_closing_quote
 4295                            {
 4296                                let anchor = snapshot.anchor_before(selection.end);
 4297                                new_selections.push((selection.map(|_| anchor), text.len()));
 4298                                new_autoclose_regions.push((
 4299                                    anchor,
 4300                                    text.len(),
 4301                                    selection.id,
 4302                                    bracket_pair.clone(),
 4303                                ));
 4304                                edits.push((
 4305                                    selection.range(),
 4306                                    format!("{}{}", text, bracket_pair.end).into(),
 4307                                ));
 4308                                bracket_inserted = true;
 4309                                continue;
 4310                            }
 4311                        }
 4312
 4313                        if let Some(region) = autoclose_region {
 4314                            // If the selection is followed by an auto-inserted closing bracket,
 4315                            // then don't insert that closing bracket again; just move the selection
 4316                            // past the closing bracket.
 4317                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 4318                                && text.as_ref() == region.pair.end.as_str()
 4319                                && snapshot.contains_str_at(region.range.end, text.as_ref());
 4320                            if should_skip {
 4321                                let anchor = snapshot.anchor_after(selection.end);
 4322                                new_selections
 4323                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 4324                                continue;
 4325                            }
 4326                        }
 4327
 4328                        let always_treat_brackets_as_autoclosed = snapshot
 4329                            .language_settings_at(selection.start, cx)
 4330                            .always_treat_brackets_as_autoclosed;
 4331                        if always_treat_brackets_as_autoclosed
 4332                            && is_bracket_pair_end
 4333                            && snapshot.contains_str_at(selection.end, text.as_ref())
 4334                        {
 4335                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 4336                            // and the inserted text is a closing bracket and the selection is followed
 4337                            // by the closing bracket then move the selection past the closing bracket.
 4338                            let anchor = snapshot.anchor_after(selection.end);
 4339                            new_selections.push((selection.map(|_| anchor), text.len()));
 4340                            continue;
 4341                        }
 4342                    }
 4343                    // If an opening bracket is 1 character long and is typed while
 4344                    // text is selected, then surround that text with the bracket pair.
 4345                    else if auto_surround
 4346                        && bracket_pair.surround
 4347                        && is_bracket_pair_start
 4348                        && bracket_pair.start.chars().count() == 1
 4349                    {
 4350                        edits.push((selection.start..selection.start, text.clone()));
 4351                        edits.push((
 4352                            selection.end..selection.end,
 4353                            bracket_pair.end.as_str().into(),
 4354                        ));
 4355                        bracket_inserted = true;
 4356                        new_selections.push((
 4357                            Selection {
 4358                                id: selection.id,
 4359                                start: snapshot.anchor_after(selection.start),
 4360                                end: snapshot.anchor_before(selection.end),
 4361                                reversed: selection.reversed,
 4362                                goal: selection.goal,
 4363                            },
 4364                            0,
 4365                        ));
 4366                        continue;
 4367                    }
 4368                }
 4369            }
 4370
 4371            if self.auto_replace_emoji_shortcode
 4372                && selection.is_empty()
 4373                && text.as_ref().ends_with(':')
 4374                && let Some(possible_emoji_short_code) =
 4375                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 4376                && !possible_emoji_short_code.is_empty()
 4377                && let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code)
 4378            {
 4379                let emoji_shortcode_start = Point::new(
 4380                    selection.start.row,
 4381                    selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 4382                );
 4383
 4384                // Remove shortcode from buffer
 4385                edits.push((
 4386                    emoji_shortcode_start..selection.start,
 4387                    "".to_string().into(),
 4388                ));
 4389                new_selections.push((
 4390                    Selection {
 4391                        id: selection.id,
 4392                        start: snapshot.anchor_after(emoji_shortcode_start),
 4393                        end: snapshot.anchor_before(selection.start),
 4394                        reversed: selection.reversed,
 4395                        goal: selection.goal,
 4396                    },
 4397                    0,
 4398                ));
 4399
 4400                // Insert emoji
 4401                let selection_start_anchor = snapshot.anchor_after(selection.start);
 4402                new_selections.push((selection.map(|_| selection_start_anchor), 0));
 4403                edits.push((selection.start..selection.end, emoji.to_string().into()));
 4404
 4405                continue;
 4406            }
 4407
 4408            // If not handling any auto-close operation, then just replace the selected
 4409            // text with the given input and move the selection to the end of the
 4410            // newly inserted text.
 4411            let anchor = snapshot.anchor_after(selection.end);
 4412            if !self.linked_edit_ranges.is_empty() {
 4413                let start_anchor = snapshot.anchor_before(selection.start);
 4414
 4415                let is_word_char = text.chars().next().is_none_or(|char| {
 4416                    let classifier = snapshot
 4417                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 4418                        .scope_context(Some(CharScopeContext::LinkedEdit));
 4419                    classifier.is_word(char)
 4420                });
 4421
 4422                if is_word_char {
 4423                    if let Some(ranges) = self
 4424                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 4425                    {
 4426                        for (buffer, edits) in ranges {
 4427                            linked_edits
 4428                                .entry(buffer.clone())
 4429                                .or_default()
 4430                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 4431                        }
 4432                    }
 4433                } else {
 4434                    clear_linked_edit_ranges = true;
 4435                }
 4436            }
 4437
 4438            new_selections.push((selection.map(|_| anchor), 0));
 4439            edits.push((selection.start..selection.end, text.clone()));
 4440        }
 4441
 4442        drop(snapshot);
 4443
 4444        self.transact(window, cx, |this, window, cx| {
 4445            if clear_linked_edit_ranges {
 4446                this.linked_edit_ranges.clear();
 4447            }
 4448            let initial_buffer_versions =
 4449                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 4450
 4451            this.buffer.update(cx, |buffer, cx| {
 4452                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 4453            });
 4454            for (buffer, edits) in linked_edits {
 4455                buffer.update(cx, |buffer, cx| {
 4456                    let snapshot = buffer.snapshot();
 4457                    let edits = edits
 4458                        .into_iter()
 4459                        .map(|(range, text)| {
 4460                            use text::ToPoint as TP;
 4461                            let end_point = TP::to_point(&range.end, &snapshot);
 4462                            let start_point = TP::to_point(&range.start, &snapshot);
 4463                            (start_point..end_point, text)
 4464                        })
 4465                        .sorted_by_key(|(range, _)| range.start);
 4466                    buffer.edit(edits, None, cx);
 4467                })
 4468            }
 4469            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 4470            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 4471            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 4472            let new_selections =
 4473                resolve_selections_wrapping_blocks::<usize, _>(new_anchor_selections, &map)
 4474                    .zip(new_selection_deltas)
 4475                    .map(|(selection, delta)| Selection {
 4476                        id: selection.id,
 4477                        start: selection.start + delta,
 4478                        end: selection.end + delta,
 4479                        reversed: selection.reversed,
 4480                        goal: SelectionGoal::None,
 4481                    })
 4482                    .collect::<Vec<_>>();
 4483
 4484            let mut i = 0;
 4485            for (position, delta, selection_id, pair) in new_autoclose_regions {
 4486                let position = position.to_offset(map.buffer_snapshot()) + delta;
 4487                let start = map.buffer_snapshot().anchor_before(position);
 4488                let end = map.buffer_snapshot().anchor_after(position);
 4489                while let Some(existing_state) = this.autoclose_regions.get(i) {
 4490                    match existing_state
 4491                        .range
 4492                        .start
 4493                        .cmp(&start, map.buffer_snapshot())
 4494                    {
 4495                        Ordering::Less => i += 1,
 4496                        Ordering::Greater => break,
 4497                        Ordering::Equal => {
 4498                            match end.cmp(&existing_state.range.end, map.buffer_snapshot()) {
 4499                                Ordering::Less => i += 1,
 4500                                Ordering::Equal => break,
 4501                                Ordering::Greater => break,
 4502                            }
 4503                        }
 4504                    }
 4505                }
 4506                this.autoclose_regions.insert(
 4507                    i,
 4508                    AutocloseRegion {
 4509                        selection_id,
 4510                        range: start..end,
 4511                        pair,
 4512                    },
 4513                );
 4514            }
 4515
 4516            let had_active_edit_prediction = this.has_active_edit_prediction();
 4517            this.change_selections(
 4518                SelectionEffects::scroll(Autoscroll::fit()).completions(false),
 4519                window,
 4520                cx,
 4521                |s| s.select(new_selections),
 4522            );
 4523
 4524            if !bracket_inserted
 4525                && let Some(on_type_format_task) =
 4526                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 4527            {
 4528                on_type_format_task.detach_and_log_err(cx);
 4529            }
 4530
 4531            let editor_settings = EditorSettings::get_global(cx);
 4532            if bracket_inserted
 4533                && (editor_settings.auto_signature_help
 4534                    || editor_settings.show_signature_help_after_edits)
 4535            {
 4536                this.show_signature_help(&ShowSignatureHelp, window, cx);
 4537            }
 4538
 4539            let trigger_in_words =
 4540                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
 4541            if this.hard_wrap.is_some() {
 4542                let latest: Range<Point> = this.selections.newest(&map).range();
 4543                if latest.is_empty()
 4544                    && this
 4545                        .buffer()
 4546                        .read(cx)
 4547                        .snapshot(cx)
 4548                        .line_len(MultiBufferRow(latest.start.row))
 4549                        == latest.start.column
 4550                {
 4551                    this.rewrap_impl(
 4552                        RewrapOptions {
 4553                            override_language_settings: true,
 4554                            preserve_existing_whitespace: true,
 4555                        },
 4556                        cx,
 4557                    )
 4558                }
 4559            }
 4560            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4561            refresh_linked_ranges(this, window, cx);
 4562            this.refresh_edit_prediction(true, false, window, cx);
 4563            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4564        });
 4565    }
 4566
 4567    fn find_possible_emoji_shortcode_at_position(
 4568        snapshot: &MultiBufferSnapshot,
 4569        position: Point,
 4570    ) -> Option<String> {
 4571        let mut chars = Vec::new();
 4572        let mut found_colon = false;
 4573        for char in snapshot.reversed_chars_at(position).take(100) {
 4574            // Found a possible emoji shortcode in the middle of the buffer
 4575            if found_colon {
 4576                if char.is_whitespace() {
 4577                    chars.reverse();
 4578                    return Some(chars.iter().collect());
 4579                }
 4580                // If the previous character is not a whitespace, we are in the middle of a word
 4581                // and we only want to complete the shortcode if the word is made up of other emojis
 4582                let mut containing_word = String::new();
 4583                for ch in snapshot
 4584                    .reversed_chars_at(position)
 4585                    .skip(chars.len() + 1)
 4586                    .take(100)
 4587                {
 4588                    if ch.is_whitespace() {
 4589                        break;
 4590                    }
 4591                    containing_word.push(ch);
 4592                }
 4593                let containing_word = containing_word.chars().rev().collect::<String>();
 4594                if util::word_consists_of_emojis(containing_word.as_str()) {
 4595                    chars.reverse();
 4596                    return Some(chars.iter().collect());
 4597                }
 4598            }
 4599
 4600            if char.is_whitespace() || !char.is_ascii() {
 4601                return None;
 4602            }
 4603            if char == ':' {
 4604                found_colon = true;
 4605            } else {
 4606                chars.push(char);
 4607            }
 4608        }
 4609        // Found a possible emoji shortcode at the beginning of the buffer
 4610        chars.reverse();
 4611        Some(chars.iter().collect())
 4612    }
 4613
 4614    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4615        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4616        self.transact(window, cx, |this, window, cx| {
 4617            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4618                let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
 4619                let multi_buffer = this.buffer.read(cx);
 4620                let buffer = multi_buffer.snapshot(cx);
 4621                selections
 4622                    .iter()
 4623                    .map(|selection| {
 4624                        let start_point = selection.start.to_point(&buffer);
 4625                        let mut existing_indent =
 4626                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4627                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4628                        let start = selection.start;
 4629                        let end = selection.end;
 4630                        let selection_is_empty = start == end;
 4631                        let language_scope = buffer.language_scope_at(start);
 4632                        let (
 4633                            comment_delimiter,
 4634                            doc_delimiter,
 4635                            insert_extra_newline,
 4636                            indent_on_newline,
 4637                            indent_on_extra_newline,
 4638                        ) = if let Some(language) = &language_scope {
 4639                            let mut insert_extra_newline =
 4640                                insert_extra_newline_brackets(&buffer, start..end, language)
 4641                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 4642
 4643                            // Comment extension on newline is allowed only for cursor selections
 4644                            let comment_delimiter = maybe!({
 4645                                if !selection_is_empty {
 4646                                    return None;
 4647                                }
 4648
 4649                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4650                                    return None;
 4651                                }
 4652
 4653                                let delimiters = language.line_comment_prefixes();
 4654                                let max_len_of_delimiter =
 4655                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 4656                                let (snapshot, range) =
 4657                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4658
 4659                                let num_of_whitespaces = snapshot
 4660                                    .chars_for_range(range.clone())
 4661                                    .take_while(|c| c.is_whitespace())
 4662                                    .count();
 4663                                let comment_candidate = snapshot
 4664                                    .chars_for_range(range.clone())
 4665                                    .skip(num_of_whitespaces)
 4666                                    .take(max_len_of_delimiter)
 4667                                    .collect::<String>();
 4668                                let (delimiter, trimmed_len) = delimiters
 4669                                    .iter()
 4670                                    .filter_map(|delimiter| {
 4671                                        let prefix = delimiter.trim_end();
 4672                                        if comment_candidate.starts_with(prefix) {
 4673                                            Some((delimiter, prefix.len()))
 4674                                        } else {
 4675                                            None
 4676                                        }
 4677                                    })
 4678                                    .max_by_key(|(_, len)| *len)?;
 4679
 4680                                if let Some(BlockCommentConfig {
 4681                                    start: block_start, ..
 4682                                }) = language.block_comment()
 4683                                {
 4684                                    let block_start_trimmed = block_start.trim_end();
 4685                                    if block_start_trimmed.starts_with(delimiter.trim_end()) {
 4686                                        let line_content = snapshot
 4687                                            .chars_for_range(range)
 4688                                            .skip(num_of_whitespaces)
 4689                                            .take(block_start_trimmed.len())
 4690                                            .collect::<String>();
 4691
 4692                                        if line_content.starts_with(block_start_trimmed) {
 4693                                            return None;
 4694                                        }
 4695                                    }
 4696                                }
 4697
 4698                                let cursor_is_placed_after_comment_marker =
 4699                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 4700                                if cursor_is_placed_after_comment_marker {
 4701                                    Some(delimiter.clone())
 4702                                } else {
 4703                                    None
 4704                                }
 4705                            });
 4706
 4707                            let mut indent_on_newline = IndentSize::spaces(0);
 4708                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 4709
 4710                            let doc_delimiter = maybe!({
 4711                                if !selection_is_empty {
 4712                                    return None;
 4713                                }
 4714
 4715                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4716                                    return None;
 4717                                }
 4718
 4719                                let BlockCommentConfig {
 4720                                    start: start_tag,
 4721                                    end: end_tag,
 4722                                    prefix: delimiter,
 4723                                    tab_size: len,
 4724                                } = language.documentation_comment()?;
 4725                                let is_within_block_comment = buffer
 4726                                    .language_scope_at(start_point)
 4727                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4728                                if !is_within_block_comment {
 4729                                    return None;
 4730                                }
 4731
 4732                                let (snapshot, range) =
 4733                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4734
 4735                                let num_of_whitespaces = snapshot
 4736                                    .chars_for_range(range.clone())
 4737                                    .take_while(|c| c.is_whitespace())
 4738                                    .count();
 4739
 4740                                // 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.
 4741                                let column = start_point.column;
 4742                                let cursor_is_after_start_tag = {
 4743                                    let start_tag_len = start_tag.len();
 4744                                    let start_tag_line = snapshot
 4745                                        .chars_for_range(range.clone())
 4746                                        .skip(num_of_whitespaces)
 4747                                        .take(start_tag_len)
 4748                                        .collect::<String>();
 4749                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4750                                        num_of_whitespaces + start_tag_len <= column as usize
 4751                                    } else {
 4752                                        false
 4753                                    }
 4754                                };
 4755
 4756                                let cursor_is_after_delimiter = {
 4757                                    let delimiter_trim = delimiter.trim_end();
 4758                                    let delimiter_line = snapshot
 4759                                        .chars_for_range(range.clone())
 4760                                        .skip(num_of_whitespaces)
 4761                                        .take(delimiter_trim.len())
 4762                                        .collect::<String>();
 4763                                    if delimiter_line.starts_with(delimiter_trim) {
 4764                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4765                                    } else {
 4766                                        false
 4767                                    }
 4768                                };
 4769
 4770                                let cursor_is_before_end_tag_if_exists = {
 4771                                    let mut char_position = 0u32;
 4772                                    let mut end_tag_offset = None;
 4773
 4774                                    'outer: for chunk in snapshot.text_for_range(range) {
 4775                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4776                                            let chars_before_match =
 4777                                                chunk[..byte_pos].chars().count() as u32;
 4778                                            end_tag_offset =
 4779                                                Some(char_position + chars_before_match);
 4780                                            break 'outer;
 4781                                        }
 4782                                        char_position += chunk.chars().count() as u32;
 4783                                    }
 4784
 4785                                    if let Some(end_tag_offset) = end_tag_offset {
 4786                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4787                                        if cursor_is_after_start_tag {
 4788                                            if cursor_is_before_end_tag {
 4789                                                insert_extra_newline = true;
 4790                                            }
 4791                                            let cursor_is_at_start_of_end_tag =
 4792                                                column == end_tag_offset;
 4793                                            if cursor_is_at_start_of_end_tag {
 4794                                                indent_on_extra_newline.len = *len;
 4795                                            }
 4796                                        }
 4797                                        cursor_is_before_end_tag
 4798                                    } else {
 4799                                        true
 4800                                    }
 4801                                };
 4802
 4803                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4804                                    && cursor_is_before_end_tag_if_exists
 4805                                {
 4806                                    if cursor_is_after_start_tag {
 4807                                        indent_on_newline.len = *len;
 4808                                    }
 4809                                    Some(delimiter.clone())
 4810                                } else {
 4811                                    None
 4812                                }
 4813                            });
 4814
 4815                            (
 4816                                comment_delimiter,
 4817                                doc_delimiter,
 4818                                insert_extra_newline,
 4819                                indent_on_newline,
 4820                                indent_on_extra_newline,
 4821                            )
 4822                        } else {
 4823                            (
 4824                                None,
 4825                                None,
 4826                                false,
 4827                                IndentSize::default(),
 4828                                IndentSize::default(),
 4829                            )
 4830                        };
 4831
 4832                        let prevent_auto_indent = doc_delimiter.is_some();
 4833                        let delimiter = comment_delimiter.or(doc_delimiter);
 4834
 4835                        let capacity_for_delimiter =
 4836                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4837                        let mut new_text = String::with_capacity(
 4838                            1 + capacity_for_delimiter
 4839                                + existing_indent.len as usize
 4840                                + indent_on_newline.len as usize
 4841                                + indent_on_extra_newline.len as usize,
 4842                        );
 4843                        new_text.push('\n');
 4844                        new_text.extend(existing_indent.chars());
 4845                        new_text.extend(indent_on_newline.chars());
 4846
 4847                        if let Some(delimiter) = &delimiter {
 4848                            new_text.push_str(delimiter);
 4849                        }
 4850
 4851                        if insert_extra_newline {
 4852                            new_text.push('\n');
 4853                            new_text.extend(existing_indent.chars());
 4854                            new_text.extend(indent_on_extra_newline.chars());
 4855                        }
 4856
 4857                        let anchor = buffer.anchor_after(end);
 4858                        let new_selection = selection.map(|_| anchor);
 4859                        (
 4860                            ((start..end, new_text), prevent_auto_indent),
 4861                            (insert_extra_newline, new_selection),
 4862                        )
 4863                    })
 4864                    .unzip()
 4865            };
 4866
 4867            let mut auto_indent_edits = Vec::new();
 4868            let mut edits = Vec::new();
 4869            for (edit, prevent_auto_indent) in edits_with_flags {
 4870                if prevent_auto_indent {
 4871                    edits.push(edit);
 4872                } else {
 4873                    auto_indent_edits.push(edit);
 4874                }
 4875            }
 4876            if !edits.is_empty() {
 4877                this.edit(edits, cx);
 4878            }
 4879            if !auto_indent_edits.is_empty() {
 4880                this.edit_with_autoindent(auto_indent_edits, cx);
 4881            }
 4882
 4883            let buffer = this.buffer.read(cx).snapshot(cx);
 4884            let new_selections = selection_info
 4885                .into_iter()
 4886                .map(|(extra_newline_inserted, new_selection)| {
 4887                    let mut cursor = new_selection.end.to_point(&buffer);
 4888                    if extra_newline_inserted {
 4889                        cursor.row -= 1;
 4890                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4891                    }
 4892                    new_selection.map(|_| cursor)
 4893                })
 4894                .collect();
 4895
 4896            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
 4897            this.refresh_edit_prediction(true, false, window, cx);
 4898        });
 4899    }
 4900
 4901    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4902        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4903
 4904        let buffer = self.buffer.read(cx);
 4905        let snapshot = buffer.snapshot(cx);
 4906
 4907        let mut edits = Vec::new();
 4908        let mut rows = Vec::new();
 4909
 4910        for (rows_inserted, selection) in self
 4911            .selections
 4912            .all_adjusted(&self.display_snapshot(cx))
 4913            .into_iter()
 4914            .enumerate()
 4915        {
 4916            let cursor = selection.head();
 4917            let row = cursor.row;
 4918
 4919            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4920
 4921            let newline = "\n".to_string();
 4922            edits.push((start_of_line..start_of_line, newline));
 4923
 4924            rows.push(row + rows_inserted as u32);
 4925        }
 4926
 4927        self.transact(window, cx, |editor, window, cx| {
 4928            editor.edit(edits, cx);
 4929
 4930            editor.change_selections(Default::default(), window, cx, |s| {
 4931                let mut index = 0;
 4932                s.move_cursors_with(|map, _, _| {
 4933                    let row = rows[index];
 4934                    index += 1;
 4935
 4936                    let point = Point::new(row, 0);
 4937                    let boundary = map.next_line_boundary(point).1;
 4938                    let clipped = map.clip_point(boundary, Bias::Left);
 4939
 4940                    (clipped, SelectionGoal::None)
 4941                });
 4942            });
 4943
 4944            let mut indent_edits = Vec::new();
 4945            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4946            for row in rows {
 4947                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4948                for (row, indent) in indents {
 4949                    if indent.len == 0 {
 4950                        continue;
 4951                    }
 4952
 4953                    let text = match indent.kind {
 4954                        IndentKind::Space => " ".repeat(indent.len as usize),
 4955                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4956                    };
 4957                    let point = Point::new(row.0, 0);
 4958                    indent_edits.push((point..point, text));
 4959                }
 4960            }
 4961            editor.edit(indent_edits, cx);
 4962        });
 4963    }
 4964
 4965    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 4966        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4967
 4968        let buffer = self.buffer.read(cx);
 4969        let snapshot = buffer.snapshot(cx);
 4970
 4971        let mut edits = Vec::new();
 4972        let mut rows = Vec::new();
 4973        let mut rows_inserted = 0;
 4974
 4975        for selection in self.selections.all_adjusted(&self.display_snapshot(cx)) {
 4976            let cursor = selection.head();
 4977            let row = cursor.row;
 4978
 4979            let point = Point::new(row + 1, 0);
 4980            let start_of_line = snapshot.clip_point(point, Bias::Left);
 4981
 4982            let newline = "\n".to_string();
 4983            edits.push((start_of_line..start_of_line, newline));
 4984
 4985            rows_inserted += 1;
 4986            rows.push(row + rows_inserted);
 4987        }
 4988
 4989        self.transact(window, cx, |editor, window, cx| {
 4990            editor.edit(edits, cx);
 4991
 4992            editor.change_selections(Default::default(), window, cx, |s| {
 4993                let mut index = 0;
 4994                s.move_cursors_with(|map, _, _| {
 4995                    let row = rows[index];
 4996                    index += 1;
 4997
 4998                    let point = Point::new(row, 0);
 4999                    let boundary = map.next_line_boundary(point).1;
 5000                    let clipped = map.clip_point(boundary, Bias::Left);
 5001
 5002                    (clipped, SelectionGoal::None)
 5003                });
 5004            });
 5005
 5006            let mut indent_edits = Vec::new();
 5007            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 5008            for row in rows {
 5009                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 5010                for (row, indent) in indents {
 5011                    if indent.len == 0 {
 5012                        continue;
 5013                    }
 5014
 5015                    let text = match indent.kind {
 5016                        IndentKind::Space => " ".repeat(indent.len as usize),
 5017                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 5018                    };
 5019                    let point = Point::new(row.0, 0);
 5020                    indent_edits.push((point..point, text));
 5021                }
 5022            }
 5023            editor.edit(indent_edits, cx);
 5024        });
 5025    }
 5026
 5027    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 5028        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 5029            original_indent_columns: Vec::new(),
 5030        });
 5031        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 5032    }
 5033
 5034    fn insert_with_autoindent_mode(
 5035        &mut self,
 5036        text: &str,
 5037        autoindent_mode: Option<AutoindentMode>,
 5038        window: &mut Window,
 5039        cx: &mut Context<Self>,
 5040    ) {
 5041        if self.read_only(cx) {
 5042            return;
 5043        }
 5044
 5045        let text: Arc<str> = text.into();
 5046        self.transact(window, cx, |this, window, cx| {
 5047            let old_selections = this.selections.all_adjusted(&this.display_snapshot(cx));
 5048            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 5049                let anchors = {
 5050                    let snapshot = buffer.read(cx);
 5051                    old_selections
 5052                        .iter()
 5053                        .map(|s| {
 5054                            let anchor = snapshot.anchor_after(s.head());
 5055                            s.map(|_| anchor)
 5056                        })
 5057                        .collect::<Vec<_>>()
 5058                };
 5059                buffer.edit(
 5060                    old_selections
 5061                        .iter()
 5062                        .map(|s| (s.start..s.end, text.clone())),
 5063                    autoindent_mode,
 5064                    cx,
 5065                );
 5066                anchors
 5067            });
 5068
 5069            this.change_selections(Default::default(), window, cx, |s| {
 5070                s.select_anchors(selection_anchors);
 5071            });
 5072
 5073            cx.notify();
 5074        });
 5075    }
 5076
 5077    fn trigger_completion_on_input(
 5078        &mut self,
 5079        text: &str,
 5080        trigger_in_words: bool,
 5081        window: &mut Window,
 5082        cx: &mut Context<Self>,
 5083    ) {
 5084        let completions_source = self
 5085            .context_menu
 5086            .borrow()
 5087            .as_ref()
 5088            .and_then(|menu| match menu {
 5089                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 5090                CodeContextMenu::CodeActions(_) => None,
 5091            });
 5092
 5093        match completions_source {
 5094            Some(CompletionsMenuSource::Words { .. }) => {
 5095                self.open_or_update_completions_menu(
 5096                    Some(CompletionsMenuSource::Words {
 5097                        ignore_threshold: false,
 5098                    }),
 5099                    None,
 5100                    trigger_in_words,
 5101                    window,
 5102                    cx,
 5103                );
 5104            }
 5105            _ => self.open_or_update_completions_menu(
 5106                None,
 5107                Some(text.to_owned()).filter(|x| !x.is_empty()),
 5108                true,
 5109                window,
 5110                cx,
 5111            ),
 5112        }
 5113    }
 5114
 5115    /// If any empty selections is touching the start of its innermost containing autoclose
 5116    /// region, expand it to select the brackets.
 5117    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 5118        let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
 5119        let buffer = self.buffer.read(cx).read(cx);
 5120        let new_selections = self
 5121            .selections_with_autoclose_regions(selections, &buffer)
 5122            .map(|(mut selection, region)| {
 5123                if !selection.is_empty() {
 5124                    return selection;
 5125                }
 5126
 5127                if let Some(region) = region {
 5128                    let mut range = region.range.to_offset(&buffer);
 5129                    if selection.start == range.start && range.start >= region.pair.start.len() {
 5130                        range.start -= region.pair.start.len();
 5131                        if buffer.contains_str_at(range.start, &region.pair.start)
 5132                            && buffer.contains_str_at(range.end, &region.pair.end)
 5133                        {
 5134                            range.end += region.pair.end.len();
 5135                            selection.start = range.start;
 5136                            selection.end = range.end;
 5137
 5138                            return selection;
 5139                        }
 5140                    }
 5141                }
 5142
 5143                let always_treat_brackets_as_autoclosed = buffer
 5144                    .language_settings_at(selection.start, cx)
 5145                    .always_treat_brackets_as_autoclosed;
 5146
 5147                if !always_treat_brackets_as_autoclosed {
 5148                    return selection;
 5149                }
 5150
 5151                if let Some(scope) = buffer.language_scope_at(selection.start) {
 5152                    for (pair, enabled) in scope.brackets() {
 5153                        if !enabled || !pair.close {
 5154                            continue;
 5155                        }
 5156
 5157                        if buffer.contains_str_at(selection.start, &pair.end) {
 5158                            let pair_start_len = pair.start.len();
 5159                            if buffer.contains_str_at(
 5160                                selection.start.saturating_sub(pair_start_len),
 5161                                &pair.start,
 5162                            ) {
 5163                                selection.start -= pair_start_len;
 5164                                selection.end += pair.end.len();
 5165
 5166                                return selection;
 5167                            }
 5168                        }
 5169                    }
 5170                }
 5171
 5172                selection
 5173            })
 5174            .collect();
 5175
 5176        drop(buffer);
 5177        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
 5178            selections.select(new_selections)
 5179        });
 5180    }
 5181
 5182    /// Iterate the given selections, and for each one, find the smallest surrounding
 5183    /// autoclose region. This uses the ordering of the selections and the autoclose
 5184    /// regions to avoid repeated comparisons.
 5185    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 5186        &'a self,
 5187        selections: impl IntoIterator<Item = Selection<D>>,
 5188        buffer: &'a MultiBufferSnapshot,
 5189    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 5190        let mut i = 0;
 5191        let mut regions = self.autoclose_regions.as_slice();
 5192        selections.into_iter().map(move |selection| {
 5193            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 5194
 5195            let mut enclosing = None;
 5196            while let Some(pair_state) = regions.get(i) {
 5197                if pair_state.range.end.to_offset(buffer) < range.start {
 5198                    regions = &regions[i + 1..];
 5199                    i = 0;
 5200                } else if pair_state.range.start.to_offset(buffer) > range.end {
 5201                    break;
 5202                } else {
 5203                    if pair_state.selection_id == selection.id {
 5204                        enclosing = Some(pair_state);
 5205                    }
 5206                    i += 1;
 5207                }
 5208            }
 5209
 5210            (selection, enclosing)
 5211        })
 5212    }
 5213
 5214    /// Remove any autoclose regions that no longer contain their selection or have invalid anchors in ranges.
 5215    fn invalidate_autoclose_regions(
 5216        &mut self,
 5217        mut selections: &[Selection<Anchor>],
 5218        buffer: &MultiBufferSnapshot,
 5219    ) {
 5220        self.autoclose_regions.retain(|state| {
 5221            if !state.range.start.is_valid(buffer) || !state.range.end.is_valid(buffer) {
 5222                return false;
 5223            }
 5224
 5225            let mut i = 0;
 5226            while let Some(selection) = selections.get(i) {
 5227                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 5228                    selections = &selections[1..];
 5229                    continue;
 5230                }
 5231                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 5232                    break;
 5233                }
 5234                if selection.id == state.selection_id {
 5235                    return true;
 5236                } else {
 5237                    i += 1;
 5238                }
 5239            }
 5240            false
 5241        });
 5242    }
 5243
 5244    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 5245        let offset = position.to_offset(buffer);
 5246        let (word_range, kind) =
 5247            buffer.surrounding_word(offset, Some(CharScopeContext::Completion));
 5248        if offset > word_range.start && kind == Some(CharKind::Word) {
 5249            Some(
 5250                buffer
 5251                    .text_for_range(word_range.start..offset)
 5252                    .collect::<String>(),
 5253            )
 5254        } else {
 5255            None
 5256        }
 5257    }
 5258
 5259    pub fn visible_excerpts(
 5260        &self,
 5261        cx: &mut Context<Editor>,
 5262    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 5263        let Some(project) = self.project() else {
 5264            return HashMap::default();
 5265        };
 5266        let project = project.read(cx);
 5267        let multi_buffer = self.buffer().read(cx);
 5268        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 5269        let multi_buffer_visible_start = self
 5270            .scroll_manager
 5271            .anchor()
 5272            .anchor
 5273            .to_point(&multi_buffer_snapshot);
 5274        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 5275            multi_buffer_visible_start
 5276                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 5277            Bias::Left,
 5278        );
 5279        multi_buffer_snapshot
 5280            .range_to_buffer_ranges(multi_buffer_visible_start..multi_buffer_visible_end)
 5281            .into_iter()
 5282            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 5283            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 5284                let buffer_file = project::File::from_dyn(buffer.file())?;
 5285                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 5286                let worktree_entry = buffer_worktree
 5287                    .read(cx)
 5288                    .entry_for_id(buffer_file.project_entry_id()?)?;
 5289                if worktree_entry.is_ignored {
 5290                    None
 5291                } else {
 5292                    Some((
 5293                        excerpt_id,
 5294                        (
 5295                            multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5296                            buffer.version().clone(),
 5297                            excerpt_visible_range,
 5298                        ),
 5299                    ))
 5300                }
 5301            })
 5302            .collect()
 5303    }
 5304
 5305    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 5306        TextLayoutDetails {
 5307            text_system: window.text_system().clone(),
 5308            editor_style: self.style.clone().unwrap(),
 5309            rem_size: window.rem_size(),
 5310            scroll_anchor: self.scroll_manager.anchor(),
 5311            visible_rows: self.visible_line_count(),
 5312            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 5313        }
 5314    }
 5315
 5316    fn trigger_on_type_formatting(
 5317        &self,
 5318        input: String,
 5319        window: &mut Window,
 5320        cx: &mut Context<Self>,
 5321    ) -> Option<Task<Result<()>>> {
 5322        if input.len() != 1 {
 5323            return None;
 5324        }
 5325
 5326        let project = self.project()?;
 5327        let position = self.selections.newest_anchor().head();
 5328        let (buffer, buffer_position) = self
 5329            .buffer
 5330            .read(cx)
 5331            .text_anchor_for_position(position, cx)?;
 5332
 5333        let settings = language_settings::language_settings(
 5334            buffer
 5335                .read(cx)
 5336                .language_at(buffer_position)
 5337                .map(|l| l.name()),
 5338            buffer.read(cx).file(),
 5339            cx,
 5340        );
 5341        if !settings.use_on_type_format {
 5342            return None;
 5343        }
 5344
 5345        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5346        // hence we do LSP request & edit on host side only — add formats to host's history.
 5347        let push_to_lsp_host_history = true;
 5348        // If this is not the host, append its history with new edits.
 5349        let push_to_client_history = project.read(cx).is_via_collab();
 5350
 5351        let on_type_formatting = project.update(cx, |project, cx| {
 5352            project.on_type_format(
 5353                buffer.clone(),
 5354                buffer_position,
 5355                input,
 5356                push_to_lsp_host_history,
 5357                cx,
 5358            )
 5359        });
 5360        Some(cx.spawn_in(window, async move |editor, cx| {
 5361            if let Some(transaction) = on_type_formatting.await? {
 5362                if push_to_client_history {
 5363                    buffer
 5364                        .update(cx, |buffer, _| {
 5365                            buffer.push_transaction(transaction, Instant::now());
 5366                            buffer.finalize_last_transaction();
 5367                        })
 5368                        .ok();
 5369                }
 5370                editor.update(cx, |editor, cx| {
 5371                    editor.refresh_document_highlights(cx);
 5372                })?;
 5373            }
 5374            Ok(())
 5375        }))
 5376    }
 5377
 5378    pub fn show_word_completions(
 5379        &mut self,
 5380        _: &ShowWordCompletions,
 5381        window: &mut Window,
 5382        cx: &mut Context<Self>,
 5383    ) {
 5384        self.open_or_update_completions_menu(
 5385            Some(CompletionsMenuSource::Words {
 5386                ignore_threshold: true,
 5387            }),
 5388            None,
 5389            false,
 5390            window,
 5391            cx,
 5392        );
 5393    }
 5394
 5395    pub fn show_completions(
 5396        &mut self,
 5397        _: &ShowCompletions,
 5398        window: &mut Window,
 5399        cx: &mut Context<Self>,
 5400    ) {
 5401        self.open_or_update_completions_menu(None, None, false, window, cx);
 5402    }
 5403
 5404    fn open_or_update_completions_menu(
 5405        &mut self,
 5406        requested_source: Option<CompletionsMenuSource>,
 5407        trigger: Option<String>,
 5408        trigger_in_words: bool,
 5409        window: &mut Window,
 5410        cx: &mut Context<Self>,
 5411    ) {
 5412        if self.pending_rename.is_some() {
 5413            return;
 5414        }
 5415
 5416        let completions_source = self
 5417            .context_menu
 5418            .borrow()
 5419            .as_ref()
 5420            .and_then(|menu| match menu {
 5421                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 5422                CodeContextMenu::CodeActions(_) => None,
 5423            });
 5424
 5425        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5426
 5427        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5428        // inserted and selected. To handle that case, the start of the selection is used so that
 5429        // the menu starts with all choices.
 5430        let position = self
 5431            .selections
 5432            .newest_anchor()
 5433            .start
 5434            .bias_right(&multibuffer_snapshot);
 5435        if position.diff_base_anchor.is_some() {
 5436            return;
 5437        }
 5438        let buffer_position = multibuffer_snapshot.anchor_before(position);
 5439        let Some(buffer) = buffer_position
 5440            .buffer_id
 5441            .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
 5442        else {
 5443            return;
 5444        };
 5445        let buffer_snapshot = buffer.read(cx).snapshot();
 5446
 5447        let query: Option<Arc<String>> =
 5448            Self::completion_query(&multibuffer_snapshot, buffer_position)
 5449                .map(|query| query.into());
 5450
 5451        drop(multibuffer_snapshot);
 5452
 5453        // Hide the current completions menu when query is empty. Without this, cached
 5454        // completions from before the trigger char may be reused (#32774).
 5455        if query.is_none() {
 5456            let menu_is_open = matches!(
 5457                self.context_menu.borrow().as_ref(),
 5458                Some(CodeContextMenu::Completions(_))
 5459            );
 5460            if menu_is_open {
 5461                self.hide_context_menu(window, cx);
 5462            }
 5463        }
 5464
 5465        let mut ignore_word_threshold = false;
 5466        let provider = match requested_source {
 5467            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5468            Some(CompletionsMenuSource::Words { ignore_threshold }) => {
 5469                ignore_word_threshold = ignore_threshold;
 5470                None
 5471            }
 5472            Some(CompletionsMenuSource::SnippetChoices)
 5473            | Some(CompletionsMenuSource::SnippetsOnly) => {
 5474                log::error!("bug: SnippetChoices requested_source is not handled");
 5475                None
 5476            }
 5477        };
 5478
 5479        let sort_completions = provider
 5480            .as_ref()
 5481            .is_some_and(|provider| provider.sort_completions());
 5482
 5483        let filter_completions = provider
 5484            .as_ref()
 5485            .is_none_or(|provider| provider.filter_completions());
 5486
 5487        let was_snippets_only = matches!(
 5488            completions_source,
 5489            Some(CompletionsMenuSource::SnippetsOnly)
 5490        );
 5491
 5492        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5493            if filter_completions {
 5494                menu.filter(query.clone(), provider.clone(), window, cx);
 5495            }
 5496            // When `is_incomplete` is false, no need to re-query completions when the current query
 5497            // is a suffix of the initial query.
 5498            let was_complete = !menu.is_incomplete;
 5499            if was_complete && !was_snippets_only {
 5500                // If the new query is a suffix of the old query (typing more characters) and
 5501                // the previous result was complete, the existing completions can be filtered.
 5502                //
 5503                // Note that this is always true for snippet completions.
 5504                let query_matches = match (&menu.initial_query, &query) {
 5505                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5506                    (None, _) => true,
 5507                    _ => false,
 5508                };
 5509                if query_matches {
 5510                    let position_matches = if menu.initial_position == position {
 5511                        true
 5512                    } else {
 5513                        let snapshot = self.buffer.read(cx).read(cx);
 5514                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5515                    };
 5516                    if position_matches {
 5517                        return;
 5518                    }
 5519                }
 5520            }
 5521        };
 5522
 5523        let Anchor {
 5524            excerpt_id: buffer_excerpt_id,
 5525            text_anchor: buffer_position,
 5526            ..
 5527        } = buffer_position;
 5528
 5529        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5530            buffer_snapshot.surrounding_word(buffer_position, None)
 5531        {
 5532            let word_to_exclude = buffer_snapshot
 5533                .text_for_range(word_range.clone())
 5534                .collect::<String>();
 5535            (
 5536                buffer_snapshot.anchor_before(word_range.start)
 5537                    ..buffer_snapshot.anchor_after(buffer_position),
 5538                Some(word_to_exclude),
 5539            )
 5540        } else {
 5541            (buffer_position..buffer_position, None)
 5542        };
 5543
 5544        let language = buffer_snapshot
 5545            .language_at(buffer_position)
 5546            .map(|language| language.name());
 5547
 5548        let completion_settings = language_settings(language.clone(), buffer_snapshot.file(), cx)
 5549            .completions
 5550            .clone();
 5551
 5552        let show_completion_documentation = buffer_snapshot
 5553            .settings_at(buffer_position, cx)
 5554            .show_completion_documentation;
 5555
 5556        // The document can be large, so stay in reasonable bounds when searching for words,
 5557        // otherwise completion pop-up might be slow to appear.
 5558        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5559        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5560        let min_word_search = buffer_snapshot.clip_point(
 5561            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5562            Bias::Left,
 5563        );
 5564        let max_word_search = buffer_snapshot.clip_point(
 5565            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5566            Bias::Right,
 5567        );
 5568        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5569            ..buffer_snapshot.point_to_offset(max_word_search);
 5570
 5571        let skip_digits = query
 5572            .as_ref()
 5573            .is_none_or(|query| !query.chars().any(|c| c.is_digit(10)));
 5574
 5575        let load_provider_completions = provider.as_ref().is_some_and(|provider| {
 5576            trigger.as_ref().is_none_or(|trigger| {
 5577                provider.is_completion_trigger(
 5578                    &buffer,
 5579                    position.text_anchor,
 5580                    trigger,
 5581                    trigger_in_words,
 5582                    completions_source.is_some(),
 5583                    cx,
 5584                )
 5585            })
 5586        });
 5587
 5588        let provider_responses = if let Some(provider) = &provider
 5589            && load_provider_completions
 5590        {
 5591            let trigger_character =
 5592                trigger.filter(|trigger| buffer.read(cx).completion_triggers().contains(trigger));
 5593            let completion_context = CompletionContext {
 5594                trigger_kind: match &trigger_character {
 5595                    Some(_) => CompletionTriggerKind::TRIGGER_CHARACTER,
 5596                    None => CompletionTriggerKind::INVOKED,
 5597                },
 5598                trigger_character,
 5599            };
 5600
 5601            provider.completions(
 5602                buffer_excerpt_id,
 5603                &buffer,
 5604                buffer_position,
 5605                completion_context,
 5606                window,
 5607                cx,
 5608            )
 5609        } else {
 5610            Task::ready(Ok(Vec::new()))
 5611        };
 5612
 5613        let load_word_completions = if !self.word_completions_enabled {
 5614            false
 5615        } else if requested_source
 5616            == Some(CompletionsMenuSource::Words {
 5617                ignore_threshold: true,
 5618            })
 5619        {
 5620            true
 5621        } else {
 5622            load_provider_completions
 5623                && completion_settings.words != WordsCompletionMode::Disabled
 5624                && (ignore_word_threshold || {
 5625                    let words_min_length = completion_settings.words_min_length;
 5626                    // check whether word has at least `words_min_length` characters
 5627                    let query_chars = query.iter().flat_map(|q| q.chars());
 5628                    query_chars.take(words_min_length).count() == words_min_length
 5629                })
 5630        };
 5631
 5632        let mut words = if load_word_completions {
 5633            cx.background_spawn(async move {
 5634                buffer_snapshot.words_in_range(WordsQuery {
 5635                    fuzzy_contents: None,
 5636                    range: word_search_range,
 5637                    skip_digits,
 5638                })
 5639            })
 5640        } else {
 5641            Task::ready(BTreeMap::default())
 5642        };
 5643
 5644        let snippets = if let Some(provider) = &provider
 5645            && provider.show_snippets()
 5646            && let Some(project) = self.project()
 5647        {
 5648            project.update(cx, |project, cx| {
 5649                snippet_completions(project, &buffer, buffer_position, cx)
 5650            })
 5651        } else {
 5652            Task::ready(Ok(CompletionResponse {
 5653                completions: Vec::new(),
 5654                display_options: Default::default(),
 5655                is_incomplete: false,
 5656            }))
 5657        };
 5658
 5659        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5660
 5661        let id = post_inc(&mut self.next_completion_id);
 5662        let task = cx.spawn_in(window, async move |editor, cx| {
 5663            let Ok(()) = editor.update(cx, |this, _| {
 5664                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5665            }) else {
 5666                return;
 5667            };
 5668
 5669            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5670            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5671            let mut completions = Vec::new();
 5672            let mut is_incomplete = false;
 5673            let mut display_options: Option<CompletionDisplayOptions> = None;
 5674            if let Some(provider_responses) = provider_responses.await.log_err()
 5675                && !provider_responses.is_empty()
 5676            {
 5677                for response in provider_responses {
 5678                    completions.extend(response.completions);
 5679                    is_incomplete = is_incomplete || response.is_incomplete;
 5680                    match display_options.as_mut() {
 5681                        None => {
 5682                            display_options = Some(response.display_options);
 5683                        }
 5684                        Some(options) => options.merge(&response.display_options),
 5685                    }
 5686                }
 5687                if completion_settings.words == WordsCompletionMode::Fallback {
 5688                    words = Task::ready(BTreeMap::default());
 5689                }
 5690            }
 5691            let display_options = display_options.unwrap_or_default();
 5692
 5693            let mut words = words.await;
 5694            if let Some(word_to_exclude) = &word_to_exclude {
 5695                words.remove(word_to_exclude);
 5696            }
 5697            for lsp_completion in &completions {
 5698                words.remove(&lsp_completion.new_text);
 5699            }
 5700            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5701                replace_range: word_replace_range.clone(),
 5702                new_text: word.clone(),
 5703                label: CodeLabel::plain(word, None),
 5704                icon_path: None,
 5705                documentation: None,
 5706                source: CompletionSource::BufferWord {
 5707                    word_range,
 5708                    resolved: false,
 5709                },
 5710                insert_text_mode: Some(InsertTextMode::AS_IS),
 5711                confirm: None,
 5712            }));
 5713
 5714            completions.extend(
 5715                snippets
 5716                    .await
 5717                    .into_iter()
 5718                    .flat_map(|response| response.completions),
 5719            );
 5720
 5721            let menu = if completions.is_empty() {
 5722                None
 5723            } else {
 5724                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5725                    let languages = editor
 5726                        .workspace
 5727                        .as_ref()
 5728                        .and_then(|(workspace, _)| workspace.upgrade())
 5729                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5730                    let menu = CompletionsMenu::new(
 5731                        id,
 5732                        requested_source.unwrap_or(if load_provider_completions {
 5733                            CompletionsMenuSource::Normal
 5734                        } else {
 5735                            CompletionsMenuSource::SnippetsOnly
 5736                        }),
 5737                        sort_completions,
 5738                        show_completion_documentation,
 5739                        position,
 5740                        query.clone(),
 5741                        is_incomplete,
 5742                        buffer.clone(),
 5743                        completions.into(),
 5744                        display_options,
 5745                        snippet_sort_order,
 5746                        languages,
 5747                        language,
 5748                        cx,
 5749                    );
 5750
 5751                    let query = if filter_completions { query } else { None };
 5752                    let matches_task = if let Some(query) = query {
 5753                        menu.do_async_filtering(query, cx)
 5754                    } else {
 5755                        Task::ready(menu.unfiltered_matches())
 5756                    };
 5757                    (menu, matches_task)
 5758                }) else {
 5759                    return;
 5760                };
 5761
 5762                let matches = matches_task.await;
 5763
 5764                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5765                    // Newer menu already set, so exit.
 5766                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5767                        editor.context_menu.borrow().as_ref()
 5768                        && prev_menu.id > id
 5769                    {
 5770                        return;
 5771                    };
 5772
 5773                    // Only valid to take prev_menu because it the new menu is immediately set
 5774                    // below, or the menu is hidden.
 5775                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5776                        editor.context_menu.borrow_mut().take()
 5777                    {
 5778                        let position_matches =
 5779                            if prev_menu.initial_position == menu.initial_position {
 5780                                true
 5781                            } else {
 5782                                let snapshot = editor.buffer.read(cx).read(cx);
 5783                                prev_menu.initial_position.to_offset(&snapshot)
 5784                                    == menu.initial_position.to_offset(&snapshot)
 5785                            };
 5786                        if position_matches {
 5787                            // Preserve markdown cache before `set_filter_results` because it will
 5788                            // try to populate the documentation cache.
 5789                            menu.preserve_markdown_cache(prev_menu);
 5790                        }
 5791                    };
 5792
 5793                    menu.set_filter_results(matches, provider, window, cx);
 5794                }) else {
 5795                    return;
 5796                };
 5797
 5798                menu.visible().then_some(menu)
 5799            };
 5800
 5801            editor
 5802                .update_in(cx, |editor, window, cx| {
 5803                    if editor.focus_handle.is_focused(window)
 5804                        && let Some(menu) = menu
 5805                    {
 5806                        *editor.context_menu.borrow_mut() =
 5807                            Some(CodeContextMenu::Completions(menu));
 5808
 5809                        crate::hover_popover::hide_hover(editor, cx);
 5810                        if editor.show_edit_predictions_in_menu() {
 5811                            editor.update_visible_edit_prediction(window, cx);
 5812                        } else {
 5813                            editor.discard_edit_prediction(false, cx);
 5814                        }
 5815
 5816                        cx.notify();
 5817                        return;
 5818                    }
 5819
 5820                    if editor.completion_tasks.len() <= 1 {
 5821                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 5822                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5823                        // If it was already hidden and we don't show edit predictions in the menu,
 5824                        // we should also show the edit prediction when available.
 5825                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5826                            editor.update_visible_edit_prediction(window, cx);
 5827                        }
 5828                    }
 5829                })
 5830                .ok();
 5831        });
 5832
 5833        self.completion_tasks.push((id, task));
 5834    }
 5835
 5836    #[cfg(feature = "test-support")]
 5837    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5838        let menu = self.context_menu.borrow();
 5839        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5840            let completions = menu.completions.borrow();
 5841            Some(completions.to_vec())
 5842        } else {
 5843            None
 5844        }
 5845    }
 5846
 5847    pub fn with_completions_menu_matching_id<R>(
 5848        &self,
 5849        id: CompletionId,
 5850        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 5851    ) -> R {
 5852        let mut context_menu = self.context_menu.borrow_mut();
 5853        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 5854            return f(None);
 5855        };
 5856        if completions_menu.id != id {
 5857            return f(None);
 5858        }
 5859        f(Some(completions_menu))
 5860    }
 5861
 5862    pub fn confirm_completion(
 5863        &mut self,
 5864        action: &ConfirmCompletion,
 5865        window: &mut Window,
 5866        cx: &mut Context<Self>,
 5867    ) -> Option<Task<Result<()>>> {
 5868        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5869        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5870    }
 5871
 5872    pub fn confirm_completion_insert(
 5873        &mut self,
 5874        _: &ConfirmCompletionInsert,
 5875        window: &mut Window,
 5876        cx: &mut Context<Self>,
 5877    ) -> Option<Task<Result<()>>> {
 5878        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5879        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5880    }
 5881
 5882    pub fn confirm_completion_replace(
 5883        &mut self,
 5884        _: &ConfirmCompletionReplace,
 5885        window: &mut Window,
 5886        cx: &mut Context<Self>,
 5887    ) -> Option<Task<Result<()>>> {
 5888        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5889        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5890    }
 5891
 5892    pub fn compose_completion(
 5893        &mut self,
 5894        action: &ComposeCompletion,
 5895        window: &mut Window,
 5896        cx: &mut Context<Self>,
 5897    ) -> Option<Task<Result<()>>> {
 5898        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5899        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5900    }
 5901
 5902    fn do_completion(
 5903        &mut self,
 5904        item_ix: Option<usize>,
 5905        intent: CompletionIntent,
 5906        window: &mut Window,
 5907        cx: &mut Context<Editor>,
 5908    ) -> Option<Task<Result<()>>> {
 5909        use language::ToOffset as _;
 5910
 5911        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5912        else {
 5913            return None;
 5914        };
 5915
 5916        let candidate_id = {
 5917            let entries = completions_menu.entries.borrow();
 5918            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5919            if self.show_edit_predictions_in_menu() {
 5920                self.discard_edit_prediction(true, cx);
 5921            }
 5922            mat.candidate_id
 5923        };
 5924
 5925        let completion = completions_menu
 5926            .completions
 5927            .borrow()
 5928            .get(candidate_id)?
 5929            .clone();
 5930        cx.stop_propagation();
 5931
 5932        let buffer_handle = completions_menu.buffer.clone();
 5933
 5934        let CompletionEdit {
 5935            new_text,
 5936            snippet,
 5937            replace_range,
 5938        } = process_completion_for_edit(
 5939            &completion,
 5940            intent,
 5941            &buffer_handle,
 5942            &completions_menu.initial_position.text_anchor,
 5943            cx,
 5944        );
 5945
 5946        let buffer = buffer_handle.read(cx);
 5947        let snapshot = self.buffer.read(cx).snapshot(cx);
 5948        let newest_anchor = self.selections.newest_anchor();
 5949        let replace_range_multibuffer = {
 5950            let mut excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 5951            excerpt.map_range_from_buffer(replace_range.clone())
 5952        };
 5953        if snapshot.buffer_id_for_anchor(newest_anchor.head()) != Some(buffer.remote_id()) {
 5954            return None;
 5955        }
 5956
 5957        let old_text = buffer
 5958            .text_for_range(replace_range.clone())
 5959            .collect::<String>();
 5960        let lookbehind = newest_anchor
 5961            .start
 5962            .text_anchor
 5963            .to_offset(buffer)
 5964            .saturating_sub(replace_range.start);
 5965        let lookahead = replace_range
 5966            .end
 5967            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 5968        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 5969        let suffix = &old_text[lookbehind.min(old_text.len())..];
 5970
 5971        let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
 5972        let mut ranges = Vec::new();
 5973        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 5974
 5975        for selection in &selections {
 5976            let range = if selection.id == newest_anchor.id {
 5977                replace_range_multibuffer.clone()
 5978            } else {
 5979                let mut range = selection.range();
 5980
 5981                // if prefix is present, don't duplicate it
 5982                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 5983                    range.start = range.start.saturating_sub(lookbehind);
 5984
 5985                    // if suffix is also present, mimic the newest cursor and replace it
 5986                    if selection.id != newest_anchor.id
 5987                        && snapshot.contains_str_at(range.end, suffix)
 5988                    {
 5989                        range.end += lookahead;
 5990                    }
 5991                }
 5992                range
 5993            };
 5994
 5995            ranges.push(range.clone());
 5996
 5997            if !self.linked_edit_ranges.is_empty() {
 5998                let start_anchor = snapshot.anchor_before(range.start);
 5999                let end_anchor = snapshot.anchor_after(range.end);
 6000                if let Some(ranges) = self
 6001                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 6002                {
 6003                    for (buffer, edits) in ranges {
 6004                        linked_edits
 6005                            .entry(buffer.clone())
 6006                            .or_default()
 6007                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 6008                    }
 6009                }
 6010            }
 6011        }
 6012
 6013        let common_prefix_len = old_text
 6014            .chars()
 6015            .zip(new_text.chars())
 6016            .take_while(|(a, b)| a == b)
 6017            .map(|(a, _)| a.len_utf8())
 6018            .sum::<usize>();
 6019
 6020        cx.emit(EditorEvent::InputHandled {
 6021            utf16_range_to_replace: None,
 6022            text: new_text[common_prefix_len..].into(),
 6023        });
 6024
 6025        self.transact(window, cx, |editor, window, cx| {
 6026            if let Some(mut snippet) = snippet {
 6027                snippet.text = new_text.to_string();
 6028                editor
 6029                    .insert_snippet(&ranges, snippet, window, cx)
 6030                    .log_err();
 6031            } else {
 6032                editor.buffer.update(cx, |multi_buffer, cx| {
 6033                    let auto_indent = match completion.insert_text_mode {
 6034                        Some(InsertTextMode::AS_IS) => None,
 6035                        _ => editor.autoindent_mode.clone(),
 6036                    };
 6037                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 6038                    multi_buffer.edit(edits, auto_indent, cx);
 6039                });
 6040            }
 6041            for (buffer, edits) in linked_edits {
 6042                buffer.update(cx, |buffer, cx| {
 6043                    let snapshot = buffer.snapshot();
 6044                    let edits = edits
 6045                        .into_iter()
 6046                        .map(|(range, text)| {
 6047                            use text::ToPoint as TP;
 6048                            let end_point = TP::to_point(&range.end, &snapshot);
 6049                            let start_point = TP::to_point(&range.start, &snapshot);
 6050                            (start_point..end_point, text)
 6051                        })
 6052                        .sorted_by_key(|(range, _)| range.start);
 6053                    buffer.edit(edits, None, cx);
 6054                })
 6055            }
 6056
 6057            editor.refresh_edit_prediction(true, false, window, cx);
 6058        });
 6059        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors_arc(), &snapshot);
 6060
 6061        let show_new_completions_on_confirm = completion
 6062            .confirm
 6063            .as_ref()
 6064            .is_some_and(|confirm| confirm(intent, window, cx));
 6065        if show_new_completions_on_confirm {
 6066            self.open_or_update_completions_menu(None, None, false, window, cx);
 6067        }
 6068
 6069        let provider = self.completion_provider.as_ref()?;
 6070        drop(completion);
 6071        let apply_edits = provider.apply_additional_edits_for_completion(
 6072            buffer_handle,
 6073            completions_menu.completions.clone(),
 6074            candidate_id,
 6075            true,
 6076            cx,
 6077        );
 6078
 6079        let editor_settings = EditorSettings::get_global(cx);
 6080        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 6081            // After the code completion is finished, users often want to know what signatures are needed.
 6082            // so we should automatically call signature_help
 6083            self.show_signature_help(&ShowSignatureHelp, window, cx);
 6084        }
 6085
 6086        Some(cx.foreground_executor().spawn(async move {
 6087            apply_edits.await?;
 6088            Ok(())
 6089        }))
 6090    }
 6091
 6092    pub fn toggle_code_actions(
 6093        &mut self,
 6094        action: &ToggleCodeActions,
 6095        window: &mut Window,
 6096        cx: &mut Context<Self>,
 6097    ) {
 6098        let quick_launch = action.quick_launch;
 6099        let mut context_menu = self.context_menu.borrow_mut();
 6100        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 6101            if code_actions.deployed_from == action.deployed_from {
 6102                // Toggle if we're selecting the same one
 6103                *context_menu = None;
 6104                cx.notify();
 6105                return;
 6106            } else {
 6107                // Otherwise, clear it and start a new one
 6108                *context_menu = None;
 6109                cx.notify();
 6110            }
 6111        }
 6112        drop(context_menu);
 6113        let snapshot = self.snapshot(window, cx);
 6114        let deployed_from = action.deployed_from.clone();
 6115        let action = action.clone();
 6116        self.completion_tasks.clear();
 6117        self.discard_edit_prediction(false, cx);
 6118
 6119        let multibuffer_point = match &action.deployed_from {
 6120            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 6121                DisplayPoint::new(*row, 0).to_point(&snapshot)
 6122            }
 6123            _ => self
 6124                .selections
 6125                .newest::<Point>(&snapshot.display_snapshot)
 6126                .head(),
 6127        };
 6128        let Some((buffer, buffer_row)) = snapshot
 6129            .buffer_snapshot()
 6130            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 6131            .and_then(|(buffer_snapshot, range)| {
 6132                self.buffer()
 6133                    .read(cx)
 6134                    .buffer(buffer_snapshot.remote_id())
 6135                    .map(|buffer| (buffer, range.start.row))
 6136            })
 6137        else {
 6138            return;
 6139        };
 6140        let buffer_id = buffer.read(cx).remote_id();
 6141        let tasks = self
 6142            .tasks
 6143            .get(&(buffer_id, buffer_row))
 6144            .map(|t| Arc::new(t.to_owned()));
 6145
 6146        if !self.focus_handle.is_focused(window) {
 6147            return;
 6148        }
 6149        let project = self.project.clone();
 6150
 6151        let code_actions_task = match deployed_from {
 6152            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 6153            _ => self.code_actions(buffer_row, window, cx),
 6154        };
 6155
 6156        let runnable_task = match deployed_from {
 6157            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 6158            _ => {
 6159                let mut task_context_task = Task::ready(None);
 6160                if let Some(tasks) = &tasks
 6161                    && let Some(project) = project
 6162                {
 6163                    task_context_task =
 6164                        Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx);
 6165                }
 6166
 6167                cx.spawn_in(window, {
 6168                    let buffer = buffer.clone();
 6169                    async move |editor, cx| {
 6170                        let task_context = task_context_task.await;
 6171
 6172                        let resolved_tasks =
 6173                            tasks
 6174                                .zip(task_context.clone())
 6175                                .map(|(tasks, task_context)| ResolvedTasks {
 6176                                    templates: tasks.resolve(&task_context).collect(),
 6177                                    position: snapshot.buffer_snapshot().anchor_before(Point::new(
 6178                                        multibuffer_point.row,
 6179                                        tasks.column,
 6180                                    )),
 6181                                });
 6182                        let debug_scenarios = editor
 6183                            .update(cx, |editor, cx| {
 6184                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 6185                            })?
 6186                            .await;
 6187                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 6188                    }
 6189                })
 6190            }
 6191        };
 6192
 6193        cx.spawn_in(window, async move |editor, cx| {
 6194            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 6195            let code_actions = code_actions_task.await;
 6196            let spawn_straight_away = quick_launch
 6197                && resolved_tasks
 6198                    .as_ref()
 6199                    .is_some_and(|tasks| tasks.templates.len() == 1)
 6200                && code_actions
 6201                    .as_ref()
 6202                    .is_none_or(|actions| actions.is_empty())
 6203                && debug_scenarios.is_empty();
 6204
 6205            editor.update_in(cx, |editor, window, cx| {
 6206                crate::hover_popover::hide_hover(editor, cx);
 6207                let actions = CodeActionContents::new(
 6208                    resolved_tasks,
 6209                    code_actions,
 6210                    debug_scenarios,
 6211                    task_context.unwrap_or_default(),
 6212                );
 6213
 6214                // Don't show the menu if there are no actions available
 6215                if actions.is_empty() {
 6216                    cx.notify();
 6217                    return Task::ready(Ok(()));
 6218                }
 6219
 6220                *editor.context_menu.borrow_mut() =
 6221                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 6222                        buffer,
 6223                        actions,
 6224                        selected_item: Default::default(),
 6225                        scroll_handle: UniformListScrollHandle::default(),
 6226                        deployed_from,
 6227                    }));
 6228                cx.notify();
 6229                if spawn_straight_away
 6230                    && let Some(task) = editor.confirm_code_action(
 6231                        &ConfirmCodeAction { item_ix: Some(0) },
 6232                        window,
 6233                        cx,
 6234                    )
 6235                {
 6236                    return task;
 6237                }
 6238
 6239                Task::ready(Ok(()))
 6240            })
 6241        })
 6242        .detach_and_log_err(cx);
 6243    }
 6244
 6245    fn debug_scenarios(
 6246        &mut self,
 6247        resolved_tasks: &Option<ResolvedTasks>,
 6248        buffer: &Entity<Buffer>,
 6249        cx: &mut App,
 6250    ) -> Task<Vec<task::DebugScenario>> {
 6251        maybe!({
 6252            let project = self.project()?;
 6253            let dap_store = project.read(cx).dap_store();
 6254            let mut scenarios = vec![];
 6255            let resolved_tasks = resolved_tasks.as_ref()?;
 6256            let buffer = buffer.read(cx);
 6257            let language = buffer.language()?;
 6258            let file = buffer.file();
 6259            let debug_adapter = language_settings(language.name().into(), file, cx)
 6260                .debuggers
 6261                .first()
 6262                .map(SharedString::from)
 6263                .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 6264
 6265            dap_store.update(cx, |dap_store, cx| {
 6266                for (_, task) in &resolved_tasks.templates {
 6267                    let maybe_scenario = dap_store.debug_scenario_for_build_task(
 6268                        task.original_task().clone(),
 6269                        debug_adapter.clone().into(),
 6270                        task.display_label().to_owned().into(),
 6271                        cx,
 6272                    );
 6273                    scenarios.push(maybe_scenario);
 6274                }
 6275            });
 6276            Some(cx.background_spawn(async move {
 6277                futures::future::join_all(scenarios)
 6278                    .await
 6279                    .into_iter()
 6280                    .flatten()
 6281                    .collect::<Vec<_>>()
 6282            }))
 6283        })
 6284        .unwrap_or_else(|| Task::ready(vec![]))
 6285    }
 6286
 6287    fn code_actions(
 6288        &mut self,
 6289        buffer_row: u32,
 6290        window: &mut Window,
 6291        cx: &mut Context<Self>,
 6292    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 6293        let mut task = self.code_actions_task.take();
 6294        cx.spawn_in(window, async move |editor, cx| {
 6295            while let Some(prev_task) = task {
 6296                prev_task.await.log_err();
 6297                task = editor
 6298                    .update(cx, |this, _| this.code_actions_task.take())
 6299                    .ok()?;
 6300            }
 6301
 6302            editor
 6303                .update(cx, |editor, cx| {
 6304                    editor
 6305                        .available_code_actions
 6306                        .clone()
 6307                        .and_then(|(location, code_actions)| {
 6308                            let snapshot = location.buffer.read(cx).snapshot();
 6309                            let point_range = location.range.to_point(&snapshot);
 6310                            let point_range = point_range.start.row..=point_range.end.row;
 6311                            if point_range.contains(&buffer_row) {
 6312                                Some(code_actions)
 6313                            } else {
 6314                                None
 6315                            }
 6316                        })
 6317                })
 6318                .ok()
 6319                .flatten()
 6320        })
 6321    }
 6322
 6323    pub fn confirm_code_action(
 6324        &mut self,
 6325        action: &ConfirmCodeAction,
 6326        window: &mut Window,
 6327        cx: &mut Context<Self>,
 6328    ) -> Option<Task<Result<()>>> {
 6329        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6330
 6331        let actions_menu =
 6332            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 6333                menu
 6334            } else {
 6335                return None;
 6336            };
 6337
 6338        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 6339        let action = actions_menu.actions.get(action_ix)?;
 6340        let title = action.label();
 6341        let buffer = actions_menu.buffer;
 6342        let workspace = self.workspace()?;
 6343
 6344        match action {
 6345            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 6346                workspace.update(cx, |workspace, cx| {
 6347                    workspace.schedule_resolved_task(
 6348                        task_source_kind,
 6349                        resolved_task,
 6350                        false,
 6351                        window,
 6352                        cx,
 6353                    );
 6354
 6355                    Some(Task::ready(Ok(())))
 6356                })
 6357            }
 6358            CodeActionsItem::CodeAction {
 6359                excerpt_id,
 6360                action,
 6361                provider,
 6362            } => {
 6363                let apply_code_action =
 6364                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 6365                let workspace = workspace.downgrade();
 6366                Some(cx.spawn_in(window, async move |editor, cx| {
 6367                    let project_transaction = apply_code_action.await?;
 6368                    Self::open_project_transaction(
 6369                        &editor,
 6370                        workspace,
 6371                        project_transaction,
 6372                        title,
 6373                        cx,
 6374                    )
 6375                    .await
 6376                }))
 6377            }
 6378            CodeActionsItem::DebugScenario(scenario) => {
 6379                let context = actions_menu.actions.context;
 6380
 6381                workspace.update(cx, |workspace, cx| {
 6382                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 6383                    workspace.start_debug_session(
 6384                        scenario,
 6385                        context,
 6386                        Some(buffer),
 6387                        None,
 6388                        window,
 6389                        cx,
 6390                    );
 6391                });
 6392                Some(Task::ready(Ok(())))
 6393            }
 6394        }
 6395    }
 6396
 6397    pub async fn open_project_transaction(
 6398        editor: &WeakEntity<Editor>,
 6399        workspace: WeakEntity<Workspace>,
 6400        transaction: ProjectTransaction,
 6401        title: String,
 6402        cx: &mut AsyncWindowContext,
 6403    ) -> Result<()> {
 6404        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 6405        cx.update(|_, cx| {
 6406            entries.sort_unstable_by_key(|(buffer, _)| {
 6407                buffer.read(cx).file().map(|f| f.path().clone())
 6408            });
 6409        })?;
 6410        if entries.is_empty() {
 6411            return Ok(());
 6412        }
 6413
 6414        // If the project transaction's edits are all contained within this editor, then
 6415        // avoid opening a new editor to display them.
 6416
 6417        if let [(buffer, transaction)] = &*entries {
 6418            let excerpt = editor.update(cx, |editor, cx| {
 6419                editor
 6420                    .buffer()
 6421                    .read(cx)
 6422                    .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6423            })?;
 6424            if let Some((_, excerpted_buffer, excerpt_range)) = excerpt
 6425                && excerpted_buffer == *buffer
 6426            {
 6427                let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6428                    let excerpt_range = excerpt_range.to_offset(buffer);
 6429                    buffer
 6430                        .edited_ranges_for_transaction::<usize>(transaction)
 6431                        .all(|range| {
 6432                            excerpt_range.start <= range.start && excerpt_range.end >= range.end
 6433                        })
 6434                })?;
 6435
 6436                if all_edits_within_excerpt {
 6437                    return Ok(());
 6438                }
 6439            }
 6440        }
 6441
 6442        let mut ranges_to_highlight = Vec::new();
 6443        let excerpt_buffer = cx.new(|cx| {
 6444            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6445            for (buffer_handle, transaction) in &entries {
 6446                let edited_ranges = buffer_handle
 6447                    .read(cx)
 6448                    .edited_ranges_for_transaction::<Point>(transaction)
 6449                    .collect::<Vec<_>>();
 6450                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6451                    PathKey::for_buffer(buffer_handle, cx),
 6452                    buffer_handle.clone(),
 6453                    edited_ranges,
 6454                    multibuffer_context_lines(cx),
 6455                    cx,
 6456                );
 6457
 6458                ranges_to_highlight.extend(ranges);
 6459            }
 6460            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6461            multibuffer
 6462        })?;
 6463
 6464        workspace.update_in(cx, |workspace, window, cx| {
 6465            let project = workspace.project().clone();
 6466            let editor =
 6467                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6468            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6469            editor.update(cx, |editor, cx| {
 6470                editor.highlight_background::<Self>(
 6471                    &ranges_to_highlight,
 6472                    |theme| theme.colors().editor_highlighted_line_background,
 6473                    cx,
 6474                );
 6475            });
 6476        })?;
 6477
 6478        Ok(())
 6479    }
 6480
 6481    pub fn clear_code_action_providers(&mut self) {
 6482        self.code_action_providers.clear();
 6483        self.available_code_actions.take();
 6484    }
 6485
 6486    pub fn add_code_action_provider(
 6487        &mut self,
 6488        provider: Rc<dyn CodeActionProvider>,
 6489        window: &mut Window,
 6490        cx: &mut Context<Self>,
 6491    ) {
 6492        if self
 6493            .code_action_providers
 6494            .iter()
 6495            .any(|existing_provider| existing_provider.id() == provider.id())
 6496        {
 6497            return;
 6498        }
 6499
 6500        self.code_action_providers.push(provider);
 6501        self.refresh_code_actions(window, cx);
 6502    }
 6503
 6504    pub fn remove_code_action_provider(
 6505        &mut self,
 6506        id: Arc<str>,
 6507        window: &mut Window,
 6508        cx: &mut Context<Self>,
 6509    ) {
 6510        self.code_action_providers
 6511            .retain(|provider| provider.id() != id);
 6512        self.refresh_code_actions(window, cx);
 6513    }
 6514
 6515    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6516        !self.code_action_providers.is_empty()
 6517            && EditorSettings::get_global(cx).toolbar.code_actions
 6518    }
 6519
 6520    pub fn has_available_code_actions(&self) -> bool {
 6521        self.available_code_actions
 6522            .as_ref()
 6523            .is_some_and(|(_, actions)| !actions.is_empty())
 6524    }
 6525
 6526    fn render_inline_code_actions(
 6527        &self,
 6528        icon_size: ui::IconSize,
 6529        display_row: DisplayRow,
 6530        is_active: bool,
 6531        cx: &mut Context<Self>,
 6532    ) -> AnyElement {
 6533        let show_tooltip = !self.context_menu_visible();
 6534        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6535            .icon_size(icon_size)
 6536            .shape(ui::IconButtonShape::Square)
 6537            .icon_color(ui::Color::Hidden)
 6538            .toggle_state(is_active)
 6539            .when(show_tooltip, |this| {
 6540                this.tooltip({
 6541                    let focus_handle = self.focus_handle.clone();
 6542                    move |_window, cx| {
 6543                        Tooltip::for_action_in(
 6544                            "Toggle Code Actions",
 6545                            &ToggleCodeActions {
 6546                                deployed_from: None,
 6547                                quick_launch: false,
 6548                            },
 6549                            &focus_handle,
 6550                            cx,
 6551                        )
 6552                    }
 6553                })
 6554            })
 6555            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6556                window.focus(&editor.focus_handle(cx));
 6557                editor.toggle_code_actions(
 6558                    &crate::actions::ToggleCodeActions {
 6559                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6560                            display_row,
 6561                        )),
 6562                        quick_launch: false,
 6563                    },
 6564                    window,
 6565                    cx,
 6566                );
 6567            }))
 6568            .into_any_element()
 6569    }
 6570
 6571    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6572        &self.context_menu
 6573    }
 6574
 6575    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6576        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6577            cx.background_executor()
 6578                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6579                .await;
 6580
 6581            let (start_buffer, start, _, end, newest_selection) = this
 6582                .update(cx, |this, cx| {
 6583                    let newest_selection = this.selections.newest_anchor().clone();
 6584                    if newest_selection.head().diff_base_anchor.is_some() {
 6585                        return None;
 6586                    }
 6587                    let display_snapshot = this.display_snapshot(cx);
 6588                    let newest_selection_adjusted =
 6589                        this.selections.newest_adjusted(&display_snapshot);
 6590                    let buffer = this.buffer.read(cx);
 6591
 6592                    let (start_buffer, start) =
 6593                        buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6594                    let (end_buffer, end) =
 6595                        buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6596
 6597                    Some((start_buffer, start, end_buffer, end, newest_selection))
 6598                })?
 6599                .filter(|(start_buffer, _, end_buffer, _, _)| start_buffer == end_buffer)
 6600                .context(
 6601                    "Expected selection to lie in a single buffer when refreshing code actions",
 6602                )?;
 6603            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6604                let providers = this.code_action_providers.clone();
 6605                let tasks = this
 6606                    .code_action_providers
 6607                    .iter()
 6608                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6609                    .collect::<Vec<_>>();
 6610                (providers, tasks)
 6611            })?;
 6612
 6613            let mut actions = Vec::new();
 6614            for (provider, provider_actions) in
 6615                providers.into_iter().zip(future::join_all(tasks).await)
 6616            {
 6617                if let Some(provider_actions) = provider_actions.log_err() {
 6618                    actions.extend(provider_actions.into_iter().map(|action| {
 6619                        AvailableCodeAction {
 6620                            excerpt_id: newest_selection.start.excerpt_id,
 6621                            action,
 6622                            provider: provider.clone(),
 6623                        }
 6624                    }));
 6625                }
 6626            }
 6627
 6628            this.update(cx, |this, cx| {
 6629                this.available_code_actions = if actions.is_empty() {
 6630                    None
 6631                } else {
 6632                    Some((
 6633                        Location {
 6634                            buffer: start_buffer,
 6635                            range: start..end,
 6636                        },
 6637                        actions.into(),
 6638                    ))
 6639                };
 6640                cx.notify();
 6641            })
 6642        }));
 6643    }
 6644
 6645    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6646        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6647            self.show_git_blame_inline = false;
 6648
 6649            self.show_git_blame_inline_delay_task =
 6650                Some(cx.spawn_in(window, async move |this, cx| {
 6651                    cx.background_executor().timer(delay).await;
 6652
 6653                    this.update(cx, |this, cx| {
 6654                        this.show_git_blame_inline = true;
 6655                        cx.notify();
 6656                    })
 6657                    .log_err();
 6658                }));
 6659        }
 6660    }
 6661
 6662    pub fn blame_hover(&mut self, _: &BlameHover, window: &mut Window, cx: &mut Context<Self>) {
 6663        let snapshot = self.snapshot(window, cx);
 6664        let cursor = self
 6665            .selections
 6666            .newest::<Point>(&snapshot.display_snapshot)
 6667            .head();
 6668        let Some((buffer, point, _)) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)
 6669        else {
 6670            return;
 6671        };
 6672
 6673        let Some(blame) = self.blame.as_ref() else {
 6674            return;
 6675        };
 6676
 6677        let row_info = RowInfo {
 6678            buffer_id: Some(buffer.remote_id()),
 6679            buffer_row: Some(point.row),
 6680            ..Default::default()
 6681        };
 6682        let Some((buffer, blame_entry)) = blame
 6683            .update(cx, |blame, cx| blame.blame_for_rows(&[row_info], cx).next())
 6684            .flatten()
 6685        else {
 6686            return;
 6687        };
 6688
 6689        let anchor = self.selections.newest_anchor().head();
 6690        let position = self.to_pixel_point(anchor, &snapshot, window);
 6691        if let (Some(position), Some(last_bounds)) = (position, self.last_bounds) {
 6692            self.show_blame_popover(
 6693                buffer,
 6694                &blame_entry,
 6695                position + last_bounds.origin,
 6696                true,
 6697                cx,
 6698            );
 6699        };
 6700    }
 6701
 6702    fn show_blame_popover(
 6703        &mut self,
 6704        buffer: BufferId,
 6705        blame_entry: &BlameEntry,
 6706        position: gpui::Point<Pixels>,
 6707        ignore_timeout: bool,
 6708        cx: &mut Context<Self>,
 6709    ) {
 6710        if let Some(state) = &mut self.inline_blame_popover {
 6711            state.hide_task.take();
 6712        } else {
 6713            let blame_popover_delay = EditorSettings::get_global(cx).hover_popover_delay.0;
 6714            let blame_entry = blame_entry.clone();
 6715            let show_task = cx.spawn(async move |editor, cx| {
 6716                if !ignore_timeout {
 6717                    cx.background_executor()
 6718                        .timer(std::time::Duration::from_millis(blame_popover_delay))
 6719                        .await;
 6720                }
 6721                editor
 6722                    .update(cx, |editor, cx| {
 6723                        editor.inline_blame_popover_show_task.take();
 6724                        let Some(blame) = editor.blame.as_ref() else {
 6725                            return;
 6726                        };
 6727                        let blame = blame.read(cx);
 6728                        let details = blame.details_for_entry(buffer, &blame_entry);
 6729                        let markdown = cx.new(|cx| {
 6730                            Markdown::new(
 6731                                details
 6732                                    .as_ref()
 6733                                    .map(|message| message.message.clone())
 6734                                    .unwrap_or_default(),
 6735                                None,
 6736                                None,
 6737                                cx,
 6738                            )
 6739                        });
 6740                        editor.inline_blame_popover = Some(InlineBlamePopover {
 6741                            position,
 6742                            hide_task: None,
 6743                            popover_bounds: None,
 6744                            popover_state: InlineBlamePopoverState {
 6745                                scroll_handle: ScrollHandle::new(),
 6746                                commit_message: details,
 6747                                markdown,
 6748                            },
 6749                            keyboard_grace: ignore_timeout,
 6750                        });
 6751                        cx.notify();
 6752                    })
 6753                    .ok();
 6754            });
 6755            self.inline_blame_popover_show_task = Some(show_task);
 6756        }
 6757    }
 6758
 6759    fn hide_blame_popover(&mut self, ignore_timeout: bool, cx: &mut Context<Self>) -> bool {
 6760        self.inline_blame_popover_show_task.take();
 6761        if let Some(state) = &mut self.inline_blame_popover {
 6762            let hide_task = cx.spawn(async move |editor, cx| {
 6763                if !ignore_timeout {
 6764                    cx.background_executor()
 6765                        .timer(std::time::Duration::from_millis(100))
 6766                        .await;
 6767                }
 6768                editor
 6769                    .update(cx, |editor, cx| {
 6770                        editor.inline_blame_popover.take();
 6771                        cx.notify();
 6772                    })
 6773                    .ok();
 6774            });
 6775            state.hide_task = Some(hide_task);
 6776            true
 6777        } else {
 6778            false
 6779        }
 6780    }
 6781
 6782    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 6783        if self.pending_rename.is_some() {
 6784            return None;
 6785        }
 6786
 6787        let provider = self.semantics_provider.clone()?;
 6788        let buffer = self.buffer.read(cx);
 6789        let newest_selection = self.selections.newest_anchor().clone();
 6790        let cursor_position = newest_selection.head();
 6791        let (cursor_buffer, cursor_buffer_position) =
 6792            buffer.text_anchor_for_position(cursor_position, cx)?;
 6793        let (tail_buffer, tail_buffer_position) =
 6794            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 6795        if cursor_buffer != tail_buffer {
 6796            return None;
 6797        }
 6798
 6799        let snapshot = cursor_buffer.read(cx).snapshot();
 6800        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position, None);
 6801        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position, None);
 6802        if start_word_range != end_word_range {
 6803            self.document_highlights_task.take();
 6804            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6805            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6806            return None;
 6807        }
 6808
 6809        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce.0;
 6810        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6811            cx.background_executor()
 6812                .timer(Duration::from_millis(debounce))
 6813                .await;
 6814
 6815            let highlights = if let Some(highlights) = cx
 6816                .update(|cx| {
 6817                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 6818                })
 6819                .ok()
 6820                .flatten()
 6821            {
 6822                highlights.await.log_err()
 6823            } else {
 6824                None
 6825            };
 6826
 6827            if let Some(highlights) = highlights {
 6828                this.update(cx, |this, cx| {
 6829                    if this.pending_rename.is_some() {
 6830                        return;
 6831                    }
 6832
 6833                    let buffer = this.buffer.read(cx);
 6834                    if buffer
 6835                        .text_anchor_for_position(cursor_position, cx)
 6836                        .is_none_or(|(buffer, _)| buffer != cursor_buffer)
 6837                    {
 6838                        return;
 6839                    }
 6840
 6841                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 6842                    let mut write_ranges = Vec::new();
 6843                    let mut read_ranges = Vec::new();
 6844                    for highlight in highlights {
 6845                        let buffer_id = cursor_buffer.read(cx).remote_id();
 6846                        for (excerpt_id, excerpt_range) in buffer.excerpts_for_buffer(buffer_id, cx)
 6847                        {
 6848                            let start = highlight
 6849                                .range
 6850                                .start
 6851                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 6852                            let end = highlight
 6853                                .range
 6854                                .end
 6855                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6856                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6857                                continue;
 6858                            }
 6859
 6860                            let range =
 6861                                Anchor::range_in_buffer(excerpt_id, buffer_id, *start..*end);
 6862                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 6863                                write_ranges.push(range);
 6864                            } else {
 6865                                read_ranges.push(range);
 6866                            }
 6867                        }
 6868                    }
 6869
 6870                    this.highlight_background::<DocumentHighlightRead>(
 6871                        &read_ranges,
 6872                        |theme| theme.colors().editor_document_highlight_read_background,
 6873                        cx,
 6874                    );
 6875                    this.highlight_background::<DocumentHighlightWrite>(
 6876                        &write_ranges,
 6877                        |theme| theme.colors().editor_document_highlight_write_background,
 6878                        cx,
 6879                    );
 6880                    cx.notify();
 6881                })
 6882                .log_err();
 6883            }
 6884        }));
 6885        None
 6886    }
 6887
 6888    fn prepare_highlight_query_from_selection(
 6889        &mut self,
 6890        window: &Window,
 6891        cx: &mut Context<Editor>,
 6892    ) -> Option<(String, Range<Anchor>)> {
 6893        if matches!(self.mode, EditorMode::SingleLine) {
 6894            return None;
 6895        }
 6896        if !EditorSettings::get_global(cx).selection_highlight {
 6897            return None;
 6898        }
 6899        if self.selections.count() != 1 || self.selections.line_mode() {
 6900            return None;
 6901        }
 6902        let snapshot = self.snapshot(window, cx);
 6903        let selection = self.selections.newest::<Point>(&snapshot);
 6904        // If the selection spans multiple rows OR it is empty
 6905        if selection.start.row != selection.end.row
 6906            || selection.start.column == selection.end.column
 6907        {
 6908            return None;
 6909        }
 6910        let selection_anchor_range = selection.range().to_anchors(snapshot.buffer_snapshot());
 6911        let query = snapshot
 6912            .buffer_snapshot()
 6913            .text_for_range(selection_anchor_range.clone())
 6914            .collect::<String>();
 6915        if query.trim().is_empty() {
 6916            return None;
 6917        }
 6918        Some((query, selection_anchor_range))
 6919    }
 6920
 6921    fn update_selection_occurrence_highlights(
 6922        &mut self,
 6923        query_text: String,
 6924        query_range: Range<Anchor>,
 6925        multi_buffer_range_to_query: Range<Point>,
 6926        use_debounce: bool,
 6927        window: &mut Window,
 6928        cx: &mut Context<Editor>,
 6929    ) -> Task<()> {
 6930        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6931        cx.spawn_in(window, async move |editor, cx| {
 6932            if use_debounce {
 6933                cx.background_executor()
 6934                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 6935                    .await;
 6936            }
 6937            let match_task = cx.background_spawn(async move {
 6938                let buffer_ranges = multi_buffer_snapshot
 6939                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 6940                    .into_iter()
 6941                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 6942                let mut match_ranges = Vec::new();
 6943                let Ok(regex) = project::search::SearchQuery::text(
 6944                    query_text.clone(),
 6945                    false,
 6946                    false,
 6947                    false,
 6948                    Default::default(),
 6949                    Default::default(),
 6950                    false,
 6951                    None,
 6952                ) else {
 6953                    return Vec::default();
 6954                };
 6955                let query_range = query_range.to_anchors(&multi_buffer_snapshot);
 6956                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 6957                    match_ranges.extend(
 6958                        regex
 6959                            .search(buffer_snapshot, Some(search_range.clone()))
 6960                            .await
 6961                            .into_iter()
 6962                            .filter_map(|match_range| {
 6963                                let match_start = buffer_snapshot
 6964                                    .anchor_after(search_range.start + match_range.start);
 6965                                let match_end = buffer_snapshot
 6966                                    .anchor_before(search_range.start + match_range.end);
 6967                                let match_anchor_range = Anchor::range_in_buffer(
 6968                                    excerpt_id,
 6969                                    buffer_snapshot.remote_id(),
 6970                                    match_start..match_end,
 6971                                );
 6972                                (match_anchor_range != query_range).then_some(match_anchor_range)
 6973                            }),
 6974                    );
 6975                }
 6976                match_ranges
 6977            });
 6978            let match_ranges = match_task.await;
 6979            editor
 6980                .update_in(cx, |editor, _, cx| {
 6981                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 6982                    if !match_ranges.is_empty() {
 6983                        editor.highlight_background::<SelectedTextHighlight>(
 6984                            &match_ranges,
 6985                            |theme| theme.colors().editor_document_highlight_bracket_background,
 6986                            cx,
 6987                        )
 6988                    }
 6989                })
 6990                .log_err();
 6991        })
 6992    }
 6993
 6994    fn refresh_single_line_folds(&mut self, window: &mut Window, cx: &mut Context<Editor>) {
 6995        struct NewlineFold;
 6996        let type_id = std::any::TypeId::of::<NewlineFold>();
 6997        if !self.mode.is_single_line() {
 6998            return;
 6999        }
 7000        let snapshot = self.snapshot(window, cx);
 7001        if snapshot.buffer_snapshot().max_point().row == 0 {
 7002            return;
 7003        }
 7004        let task = cx.background_spawn(async move {
 7005            let new_newlines = snapshot
 7006                .buffer_chars_at(0)
 7007                .filter_map(|(c, i)| {
 7008                    if c == '\n' {
 7009                        Some(
 7010                            snapshot.buffer_snapshot().anchor_after(i)
 7011                                ..snapshot.buffer_snapshot().anchor_before(i + 1),
 7012                        )
 7013                    } else {
 7014                        None
 7015                    }
 7016                })
 7017                .collect::<Vec<_>>();
 7018            let existing_newlines = snapshot
 7019                .folds_in_range(0..snapshot.buffer_snapshot().len())
 7020                .filter_map(|fold| {
 7021                    if fold.placeholder.type_tag == Some(type_id) {
 7022                        Some(fold.range.start..fold.range.end)
 7023                    } else {
 7024                        None
 7025                    }
 7026                })
 7027                .collect::<Vec<_>>();
 7028
 7029            (new_newlines, existing_newlines)
 7030        });
 7031        self.folding_newlines = cx.spawn(async move |this, cx| {
 7032            let (new_newlines, existing_newlines) = task.await;
 7033            if new_newlines == existing_newlines {
 7034                return;
 7035            }
 7036            let placeholder = FoldPlaceholder {
 7037                render: Arc::new(move |_, _, cx| {
 7038                    div()
 7039                        .bg(cx.theme().status().hint_background)
 7040                        .border_b_1()
 7041                        .size_full()
 7042                        .font(ThemeSettings::get_global(cx).buffer_font.clone())
 7043                        .border_color(cx.theme().status().hint)
 7044                        .child("\\n")
 7045                        .into_any()
 7046                }),
 7047                constrain_width: false,
 7048                merge_adjacent: false,
 7049                type_tag: Some(type_id),
 7050            };
 7051            let creases = new_newlines
 7052                .into_iter()
 7053                .map(|range| Crease::simple(range, placeholder.clone()))
 7054                .collect();
 7055            this.update(cx, |this, cx| {
 7056                this.display_map.update(cx, |display_map, cx| {
 7057                    display_map.remove_folds_with_type(existing_newlines, type_id, cx);
 7058                    display_map.fold(creases, cx);
 7059                });
 7060            })
 7061            .ok();
 7062        });
 7063    }
 7064
 7065    fn refresh_selected_text_highlights(
 7066        &mut self,
 7067        on_buffer_edit: bool,
 7068        window: &mut Window,
 7069        cx: &mut Context<Editor>,
 7070    ) {
 7071        let Some((query_text, query_range)) =
 7072            self.prepare_highlight_query_from_selection(window, cx)
 7073        else {
 7074            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 7075            self.quick_selection_highlight_task.take();
 7076            self.debounced_selection_highlight_task.take();
 7077            return;
 7078        };
 7079        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 7080        if on_buffer_edit
 7081            || self
 7082                .quick_selection_highlight_task
 7083                .as_ref()
 7084                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7085        {
 7086            let multi_buffer_visible_start = self
 7087                .scroll_manager
 7088                .anchor()
 7089                .anchor
 7090                .to_point(&multi_buffer_snapshot);
 7091            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 7092                multi_buffer_visible_start
 7093                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 7094                Bias::Left,
 7095            );
 7096            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 7097            self.quick_selection_highlight_task = Some((
 7098                query_range.clone(),
 7099                self.update_selection_occurrence_highlights(
 7100                    query_text.clone(),
 7101                    query_range.clone(),
 7102                    multi_buffer_visible_range,
 7103                    false,
 7104                    window,
 7105                    cx,
 7106                ),
 7107            ));
 7108        }
 7109        if on_buffer_edit
 7110            || self
 7111                .debounced_selection_highlight_task
 7112                .as_ref()
 7113                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7114        {
 7115            let multi_buffer_start = multi_buffer_snapshot
 7116                .anchor_before(0)
 7117                .to_point(&multi_buffer_snapshot);
 7118            let multi_buffer_end = multi_buffer_snapshot
 7119                .anchor_after(multi_buffer_snapshot.len())
 7120                .to_point(&multi_buffer_snapshot);
 7121            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 7122            self.debounced_selection_highlight_task = Some((
 7123                query_range.clone(),
 7124                self.update_selection_occurrence_highlights(
 7125                    query_text,
 7126                    query_range,
 7127                    multi_buffer_full_range,
 7128                    true,
 7129                    window,
 7130                    cx,
 7131                ),
 7132            ));
 7133        }
 7134    }
 7135
 7136    pub fn refresh_edit_prediction(
 7137        &mut self,
 7138        debounce: bool,
 7139        user_requested: bool,
 7140        window: &mut Window,
 7141        cx: &mut Context<Self>,
 7142    ) -> Option<()> {
 7143        if DisableAiSettings::get_global(cx).disable_ai {
 7144            return None;
 7145        }
 7146
 7147        let provider = self.edit_prediction_provider()?;
 7148        let cursor = self.selections.newest_anchor().head();
 7149        let (buffer, cursor_buffer_position) =
 7150            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7151
 7152        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 7153            self.discard_edit_prediction(false, cx);
 7154            return None;
 7155        }
 7156
 7157        self.update_visible_edit_prediction(window, cx);
 7158
 7159        if !user_requested
 7160            && (!self.should_show_edit_predictions()
 7161                || !self.is_focused(window)
 7162                || buffer.read(cx).is_empty())
 7163        {
 7164            self.discard_edit_prediction(false, cx);
 7165            return None;
 7166        }
 7167
 7168        provider.refresh(buffer, cursor_buffer_position, debounce, cx);
 7169        Some(())
 7170    }
 7171
 7172    fn show_edit_predictions_in_menu(&self) -> bool {
 7173        match self.edit_prediction_settings {
 7174            EditPredictionSettings::Disabled => false,
 7175            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 7176        }
 7177    }
 7178
 7179    pub fn edit_predictions_enabled(&self) -> bool {
 7180        match self.edit_prediction_settings {
 7181            EditPredictionSettings::Disabled => false,
 7182            EditPredictionSettings::Enabled { .. } => true,
 7183        }
 7184    }
 7185
 7186    fn edit_prediction_requires_modifier(&self) -> bool {
 7187        match self.edit_prediction_settings {
 7188            EditPredictionSettings::Disabled => false,
 7189            EditPredictionSettings::Enabled {
 7190                preview_requires_modifier,
 7191                ..
 7192            } => preview_requires_modifier,
 7193        }
 7194    }
 7195
 7196    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 7197        if self.edit_prediction_provider.is_none() || DisableAiSettings::get_global(cx).disable_ai {
 7198            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7199            self.discard_edit_prediction(false, cx);
 7200        } else {
 7201            let selection = self.selections.newest_anchor();
 7202            let cursor = selection.head();
 7203
 7204            if let Some((buffer, cursor_buffer_position)) =
 7205                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7206            {
 7207                self.edit_prediction_settings =
 7208                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7209            }
 7210        }
 7211    }
 7212
 7213    fn edit_prediction_settings_at_position(
 7214        &self,
 7215        buffer: &Entity<Buffer>,
 7216        buffer_position: language::Anchor,
 7217        cx: &App,
 7218    ) -> EditPredictionSettings {
 7219        if !self.mode.is_full()
 7220            || !self.show_edit_predictions_override.unwrap_or(true)
 7221            || self.edit_predictions_disabled_in_scope(buffer, buffer_position, cx)
 7222        {
 7223            return EditPredictionSettings::Disabled;
 7224        }
 7225
 7226        let buffer = buffer.read(cx);
 7227
 7228        let file = buffer.file();
 7229
 7230        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 7231            return EditPredictionSettings::Disabled;
 7232        };
 7233
 7234        let by_provider = matches!(
 7235            self.menu_edit_predictions_policy,
 7236            MenuEditPredictionsPolicy::ByProvider
 7237        );
 7238
 7239        let show_in_menu = by_provider
 7240            && self
 7241                .edit_prediction_provider
 7242                .as_ref()
 7243                .is_some_and(|provider| provider.provider.show_completions_in_menu());
 7244
 7245        let preview_requires_modifier =
 7246            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 7247
 7248        EditPredictionSettings::Enabled {
 7249            show_in_menu,
 7250            preview_requires_modifier,
 7251        }
 7252    }
 7253
 7254    fn should_show_edit_predictions(&self) -> bool {
 7255        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 7256    }
 7257
 7258    pub fn edit_prediction_preview_is_active(&self) -> bool {
 7259        matches!(
 7260            self.edit_prediction_preview,
 7261            EditPredictionPreview::Active { .. }
 7262        )
 7263    }
 7264
 7265    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 7266        let cursor = self.selections.newest_anchor().head();
 7267        if let Some((buffer, cursor_position)) =
 7268            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7269        {
 7270            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 7271        } else {
 7272            false
 7273        }
 7274    }
 7275
 7276    pub fn supports_minimap(&self, cx: &App) -> bool {
 7277        !self.minimap_visibility.disabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton
 7278    }
 7279
 7280    fn edit_predictions_enabled_in_buffer(
 7281        &self,
 7282        buffer: &Entity<Buffer>,
 7283        buffer_position: language::Anchor,
 7284        cx: &App,
 7285    ) -> bool {
 7286        maybe!({
 7287            if self.read_only(cx) {
 7288                return Some(false);
 7289            }
 7290            let provider = self.edit_prediction_provider()?;
 7291            if !provider.is_enabled(buffer, buffer_position, cx) {
 7292                return Some(false);
 7293            }
 7294            let buffer = buffer.read(cx);
 7295            let Some(file) = buffer.file() else {
 7296                return Some(true);
 7297            };
 7298            let settings = all_language_settings(Some(file), cx);
 7299            Some(settings.edit_predictions_enabled_for_file(file, cx))
 7300        })
 7301        .unwrap_or(false)
 7302    }
 7303
 7304    fn cycle_edit_prediction(
 7305        &mut self,
 7306        direction: Direction,
 7307        window: &mut Window,
 7308        cx: &mut Context<Self>,
 7309    ) -> Option<()> {
 7310        let provider = self.edit_prediction_provider()?;
 7311        let cursor = self.selections.newest_anchor().head();
 7312        let (buffer, cursor_buffer_position) =
 7313            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7314        if self.edit_predictions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 7315            return None;
 7316        }
 7317
 7318        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 7319        self.update_visible_edit_prediction(window, cx);
 7320
 7321        Some(())
 7322    }
 7323
 7324    pub fn show_edit_prediction(
 7325        &mut self,
 7326        _: &ShowEditPrediction,
 7327        window: &mut Window,
 7328        cx: &mut Context<Self>,
 7329    ) {
 7330        if !self.has_active_edit_prediction() {
 7331            self.refresh_edit_prediction(false, true, window, cx);
 7332            return;
 7333        }
 7334
 7335        self.update_visible_edit_prediction(window, cx);
 7336    }
 7337
 7338    pub fn display_cursor_names(
 7339        &mut self,
 7340        _: &DisplayCursorNames,
 7341        window: &mut Window,
 7342        cx: &mut Context<Self>,
 7343    ) {
 7344        self.show_cursor_names(window, cx);
 7345    }
 7346
 7347    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7348        self.show_cursor_names = true;
 7349        cx.notify();
 7350        cx.spawn_in(window, async move |this, cx| {
 7351            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 7352            this.update(cx, |this, cx| {
 7353                this.show_cursor_names = false;
 7354                cx.notify()
 7355            })
 7356            .ok()
 7357        })
 7358        .detach();
 7359    }
 7360
 7361    pub fn next_edit_prediction(
 7362        &mut self,
 7363        _: &NextEditPrediction,
 7364        window: &mut Window,
 7365        cx: &mut Context<Self>,
 7366    ) {
 7367        if self.has_active_edit_prediction() {
 7368            self.cycle_edit_prediction(Direction::Next, window, cx);
 7369        } else {
 7370            let is_copilot_disabled = self
 7371                .refresh_edit_prediction(false, true, window, cx)
 7372                .is_none();
 7373            if is_copilot_disabled {
 7374                cx.propagate();
 7375            }
 7376        }
 7377    }
 7378
 7379    pub fn previous_edit_prediction(
 7380        &mut self,
 7381        _: &PreviousEditPrediction,
 7382        window: &mut Window,
 7383        cx: &mut Context<Self>,
 7384    ) {
 7385        if self.has_active_edit_prediction() {
 7386            self.cycle_edit_prediction(Direction::Prev, window, cx);
 7387        } else {
 7388            let is_copilot_disabled = self
 7389                .refresh_edit_prediction(false, true, window, cx)
 7390                .is_none();
 7391            if is_copilot_disabled {
 7392                cx.propagate();
 7393            }
 7394        }
 7395    }
 7396
 7397    pub fn accept_edit_prediction(
 7398        &mut self,
 7399        _: &AcceptEditPrediction,
 7400        window: &mut Window,
 7401        cx: &mut Context<Self>,
 7402    ) {
 7403        if self.show_edit_predictions_in_menu() {
 7404            self.hide_context_menu(window, cx);
 7405        }
 7406
 7407        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7408            return;
 7409        };
 7410
 7411        match &active_edit_prediction.completion {
 7412            EditPrediction::MoveWithin { target, .. } => {
 7413                let target = *target;
 7414
 7415                if let Some(position_map) = &self.last_position_map {
 7416                    if position_map
 7417                        .visible_row_range
 7418                        .contains(&target.to_display_point(&position_map.snapshot).row())
 7419                        || !self.edit_prediction_requires_modifier()
 7420                    {
 7421                        self.unfold_ranges(&[target..target], true, false, cx);
 7422                        // Note that this is also done in vim's handler of the Tab action.
 7423                        self.change_selections(
 7424                            SelectionEffects::scroll(Autoscroll::newest()),
 7425                            window,
 7426                            cx,
 7427                            |selections| {
 7428                                selections.select_anchor_ranges([target..target]);
 7429                            },
 7430                        );
 7431                        self.clear_row_highlights::<EditPredictionPreview>();
 7432
 7433                        self.edit_prediction_preview
 7434                            .set_previous_scroll_position(None);
 7435                    } else {
 7436                        self.edit_prediction_preview
 7437                            .set_previous_scroll_position(Some(
 7438                                position_map.snapshot.scroll_anchor,
 7439                            ));
 7440
 7441                        self.highlight_rows::<EditPredictionPreview>(
 7442                            target..target,
 7443                            cx.theme().colors().editor_highlighted_line_background,
 7444                            RowHighlightOptions {
 7445                                autoscroll: true,
 7446                                ..Default::default()
 7447                            },
 7448                            cx,
 7449                        );
 7450                        self.request_autoscroll(Autoscroll::fit(), cx);
 7451                    }
 7452                }
 7453            }
 7454            EditPrediction::MoveOutside { snapshot, target } => {
 7455                if let Some(workspace) = self.workspace() {
 7456                    Self::open_editor_at_anchor(snapshot, *target, &workspace, window, cx)
 7457                        .detach_and_log_err(cx);
 7458                }
 7459            }
 7460            EditPrediction::Edit { edits, .. } => {
 7461                self.report_edit_prediction_event(
 7462                    active_edit_prediction.completion_id.clone(),
 7463                    true,
 7464                    cx,
 7465                );
 7466
 7467                if let Some(provider) = self.edit_prediction_provider() {
 7468                    provider.accept(cx);
 7469                }
 7470
 7471                // Store the transaction ID and selections before applying the edit
 7472                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 7473
 7474                let snapshot = self.buffer.read(cx).snapshot(cx);
 7475                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 7476
 7477                self.buffer.update(cx, |buffer, cx| {
 7478                    buffer.edit(edits.iter().cloned(), None, cx)
 7479                });
 7480
 7481                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 7482                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 7483                });
 7484
 7485                let selections = self.selections.disjoint_anchors_arc();
 7486                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 7487                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 7488                    if has_new_transaction {
 7489                        self.selection_history
 7490                            .insert_transaction(transaction_id_now, selections);
 7491                    }
 7492                }
 7493
 7494                self.update_visible_edit_prediction(window, cx);
 7495                if self.active_edit_prediction.is_none() {
 7496                    self.refresh_edit_prediction(true, true, window, cx);
 7497                }
 7498
 7499                cx.notify();
 7500            }
 7501        }
 7502
 7503        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 7504    }
 7505
 7506    pub fn accept_partial_edit_prediction(
 7507        &mut self,
 7508        _: &AcceptPartialEditPrediction,
 7509        window: &mut Window,
 7510        cx: &mut Context<Self>,
 7511    ) {
 7512        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7513            return;
 7514        };
 7515        if self.selections.count() != 1 {
 7516            return;
 7517        }
 7518
 7519        match &active_edit_prediction.completion {
 7520            EditPrediction::MoveWithin { target, .. } => {
 7521                let target = *target;
 7522                self.change_selections(
 7523                    SelectionEffects::scroll(Autoscroll::newest()),
 7524                    window,
 7525                    cx,
 7526                    |selections| {
 7527                        selections.select_anchor_ranges([target..target]);
 7528                    },
 7529                );
 7530            }
 7531            EditPrediction::MoveOutside { snapshot, target } => {
 7532                if let Some(workspace) = self.workspace() {
 7533                    Self::open_editor_at_anchor(snapshot, *target, &workspace, window, cx)
 7534                        .detach_and_log_err(cx);
 7535                }
 7536            }
 7537            EditPrediction::Edit { edits, .. } => {
 7538                self.report_edit_prediction_event(
 7539                    active_edit_prediction.completion_id.clone(),
 7540                    true,
 7541                    cx,
 7542                );
 7543
 7544                // Find an insertion that starts at the cursor position.
 7545                let snapshot = self.buffer.read(cx).snapshot(cx);
 7546                let cursor_offset = self
 7547                    .selections
 7548                    .newest::<usize>(&self.display_snapshot(cx))
 7549                    .head();
 7550                let insertion = edits.iter().find_map(|(range, text)| {
 7551                    let range = range.to_offset(&snapshot);
 7552                    if range.is_empty() && range.start == cursor_offset {
 7553                        Some(text)
 7554                    } else {
 7555                        None
 7556                    }
 7557                });
 7558
 7559                if let Some(text) = insertion {
 7560                    let mut partial_completion = text
 7561                        .chars()
 7562                        .by_ref()
 7563                        .take_while(|c| c.is_alphabetic())
 7564                        .collect::<String>();
 7565                    if partial_completion.is_empty() {
 7566                        partial_completion = text
 7567                            .chars()
 7568                            .by_ref()
 7569                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7570                            .collect::<String>();
 7571                    }
 7572
 7573                    cx.emit(EditorEvent::InputHandled {
 7574                        utf16_range_to_replace: None,
 7575                        text: partial_completion.clone().into(),
 7576                    });
 7577
 7578                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 7579
 7580                    self.refresh_edit_prediction(true, true, window, cx);
 7581                    cx.notify();
 7582                } else {
 7583                    self.accept_edit_prediction(&Default::default(), window, cx);
 7584                }
 7585            }
 7586        }
 7587    }
 7588
 7589    fn discard_edit_prediction(
 7590        &mut self,
 7591        should_report_edit_prediction_event: bool,
 7592        cx: &mut Context<Self>,
 7593    ) -> bool {
 7594        if should_report_edit_prediction_event {
 7595            let completion_id = self
 7596                .active_edit_prediction
 7597                .as_ref()
 7598                .and_then(|active_completion| active_completion.completion_id.clone());
 7599
 7600            self.report_edit_prediction_event(completion_id, false, cx);
 7601        }
 7602
 7603        if let Some(provider) = self.edit_prediction_provider() {
 7604            provider.discard(cx);
 7605        }
 7606
 7607        self.take_active_edit_prediction(cx)
 7608    }
 7609
 7610    fn report_edit_prediction_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7611        let Some(provider) = self.edit_prediction_provider() else {
 7612            return;
 7613        };
 7614
 7615        let Some((_, buffer, _)) = self
 7616            .buffer
 7617            .read(cx)
 7618            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7619        else {
 7620            return;
 7621        };
 7622
 7623        let extension = buffer
 7624            .read(cx)
 7625            .file()
 7626            .and_then(|file| Some(file.path().extension()?.to_string()));
 7627
 7628        let event_type = match accepted {
 7629            true => "Edit Prediction Accepted",
 7630            false => "Edit Prediction Discarded",
 7631        };
 7632        telemetry::event!(
 7633            event_type,
 7634            provider = provider.name(),
 7635            prediction_id = id,
 7636            suggestion_accepted = accepted,
 7637            file_extension = extension,
 7638        );
 7639    }
 7640
 7641    fn open_editor_at_anchor(
 7642        snapshot: &language::BufferSnapshot,
 7643        target: language::Anchor,
 7644        workspace: &Entity<Workspace>,
 7645        window: &mut Window,
 7646        cx: &mut App,
 7647    ) -> Task<Result<()>> {
 7648        workspace.update(cx, |workspace, cx| {
 7649            let path = snapshot.file().map(|file| file.full_path(cx));
 7650            let Some(path) =
 7651                path.and_then(|path| workspace.project().read(cx).find_project_path(path, cx))
 7652            else {
 7653                return Task::ready(Err(anyhow::anyhow!("Project path not found")));
 7654            };
 7655            let target = text::ToPoint::to_point(&target, snapshot);
 7656            let item = workspace.open_path(path, None, true, window, cx);
 7657            window.spawn(cx, async move |cx| {
 7658                let Some(editor) = item.await?.downcast::<Editor>() else {
 7659                    return Ok(());
 7660                };
 7661                editor
 7662                    .update_in(cx, |editor, window, cx| {
 7663                        editor.go_to_singleton_buffer_point(target, window, cx);
 7664                    })
 7665                    .ok();
 7666                anyhow::Ok(())
 7667            })
 7668        })
 7669    }
 7670
 7671    pub fn has_active_edit_prediction(&self) -> bool {
 7672        self.active_edit_prediction.is_some()
 7673    }
 7674
 7675    fn take_active_edit_prediction(&mut self, cx: &mut Context<Self>) -> bool {
 7676        let Some(active_edit_prediction) = self.active_edit_prediction.take() else {
 7677            return false;
 7678        };
 7679
 7680        self.splice_inlays(&active_edit_prediction.inlay_ids, Default::default(), cx);
 7681        self.clear_highlights::<EditPredictionHighlight>(cx);
 7682        self.stale_edit_prediction_in_menu = Some(active_edit_prediction);
 7683        true
 7684    }
 7685
 7686    /// Returns true when we're displaying the edit prediction popover below the cursor
 7687    /// like we are not previewing and the LSP autocomplete menu is visible
 7688    /// or we are in `when_holding_modifier` mode.
 7689    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7690        if self.edit_prediction_preview_is_active()
 7691            || !self.show_edit_predictions_in_menu()
 7692            || !self.edit_predictions_enabled()
 7693        {
 7694            return false;
 7695        }
 7696
 7697        if self.has_visible_completions_menu() {
 7698            return true;
 7699        }
 7700
 7701        has_completion && self.edit_prediction_requires_modifier()
 7702    }
 7703
 7704    fn handle_modifiers_changed(
 7705        &mut self,
 7706        modifiers: Modifiers,
 7707        position_map: &PositionMap,
 7708        window: &mut Window,
 7709        cx: &mut Context<Self>,
 7710    ) {
 7711        // Ensure that the edit prediction preview is updated, even when not
 7712        // enabled, if there's an active edit prediction preview.
 7713        if self.show_edit_predictions_in_menu()
 7714            || matches!(
 7715                self.edit_prediction_preview,
 7716                EditPredictionPreview::Active { .. }
 7717            )
 7718        {
 7719            self.update_edit_prediction_preview(&modifiers, window, cx);
 7720        }
 7721
 7722        self.update_selection_mode(&modifiers, position_map, window, cx);
 7723
 7724        let mouse_position = window.mouse_position();
 7725        if !position_map.text_hitbox.is_hovered(window) {
 7726            return;
 7727        }
 7728
 7729        self.update_hovered_link(
 7730            position_map.point_for_position(mouse_position),
 7731            &position_map.snapshot,
 7732            modifiers,
 7733            window,
 7734            cx,
 7735        )
 7736    }
 7737
 7738    fn is_cmd_or_ctrl_pressed(modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7739        match EditorSettings::get_global(cx).multi_cursor_modifier {
 7740            MultiCursorModifier::Alt => modifiers.secondary(),
 7741            MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 7742        }
 7743    }
 7744
 7745    fn is_alt_pressed(modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7746        match EditorSettings::get_global(cx).multi_cursor_modifier {
 7747            MultiCursorModifier::Alt => modifiers.alt,
 7748            MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 7749        }
 7750    }
 7751
 7752    fn columnar_selection_mode(
 7753        modifiers: &Modifiers,
 7754        cx: &mut Context<Self>,
 7755    ) -> Option<ColumnarMode> {
 7756        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 7757            if Self::is_cmd_or_ctrl_pressed(modifiers, cx) {
 7758                Some(ColumnarMode::FromMouse)
 7759            } else if Self::is_alt_pressed(modifiers, cx) {
 7760                Some(ColumnarMode::FromSelection)
 7761            } else {
 7762                None
 7763            }
 7764        } else {
 7765            None
 7766        }
 7767    }
 7768
 7769    fn update_selection_mode(
 7770        &mut self,
 7771        modifiers: &Modifiers,
 7772        position_map: &PositionMap,
 7773        window: &mut Window,
 7774        cx: &mut Context<Self>,
 7775    ) {
 7776        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 7777            return;
 7778        };
 7779        if self.selections.pending_anchor().is_none() {
 7780            return;
 7781        }
 7782
 7783        let mouse_position = window.mouse_position();
 7784        let point_for_position = position_map.point_for_position(mouse_position);
 7785        let position = point_for_position.previous_valid;
 7786
 7787        self.select(
 7788            SelectPhase::BeginColumnar {
 7789                position,
 7790                reset: false,
 7791                mode,
 7792                goal_column: point_for_position.exact_unclipped.column(),
 7793            },
 7794            window,
 7795            cx,
 7796        );
 7797    }
 7798
 7799    fn update_edit_prediction_preview(
 7800        &mut self,
 7801        modifiers: &Modifiers,
 7802        window: &mut Window,
 7803        cx: &mut Context<Self>,
 7804    ) {
 7805        let mut modifiers_held = false;
 7806        if let Some(accept_keystroke) = self
 7807            .accept_edit_prediction_keybind(false, window, cx)
 7808            .keystroke()
 7809        {
 7810            modifiers_held = modifiers_held
 7811                || (accept_keystroke.modifiers() == modifiers
 7812                    && accept_keystroke.modifiers().modified());
 7813        };
 7814        if let Some(accept_partial_keystroke) = self
 7815            .accept_edit_prediction_keybind(true, window, cx)
 7816            .keystroke()
 7817        {
 7818            modifiers_held = modifiers_held
 7819                || (accept_partial_keystroke.modifiers() == modifiers
 7820                    && accept_partial_keystroke.modifiers().modified());
 7821        }
 7822
 7823        if modifiers_held {
 7824            if matches!(
 7825                self.edit_prediction_preview,
 7826                EditPredictionPreview::Inactive { .. }
 7827            ) {
 7828                self.edit_prediction_preview = EditPredictionPreview::Active {
 7829                    previous_scroll_position: None,
 7830                    since: Instant::now(),
 7831                };
 7832
 7833                self.update_visible_edit_prediction(window, cx);
 7834                cx.notify();
 7835            }
 7836        } else if let EditPredictionPreview::Active {
 7837            previous_scroll_position,
 7838            since,
 7839        } = self.edit_prediction_preview
 7840        {
 7841            if let (Some(previous_scroll_position), Some(position_map)) =
 7842                (previous_scroll_position, self.last_position_map.as_ref())
 7843            {
 7844                self.set_scroll_position(
 7845                    previous_scroll_position
 7846                        .scroll_position(&position_map.snapshot.display_snapshot),
 7847                    window,
 7848                    cx,
 7849                );
 7850            }
 7851
 7852            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 7853                released_too_fast: since.elapsed() < Duration::from_millis(200),
 7854            };
 7855            self.clear_row_highlights::<EditPredictionPreview>();
 7856            self.update_visible_edit_prediction(window, cx);
 7857            cx.notify();
 7858        }
 7859    }
 7860
 7861    fn update_visible_edit_prediction(
 7862        &mut self,
 7863        _window: &mut Window,
 7864        cx: &mut Context<Self>,
 7865    ) -> Option<()> {
 7866        if DisableAiSettings::get_global(cx).disable_ai {
 7867            return None;
 7868        }
 7869
 7870        if self.ime_transaction.is_some() {
 7871            self.discard_edit_prediction(false, cx);
 7872            return None;
 7873        }
 7874
 7875        let selection = self.selections.newest_anchor();
 7876        let cursor = selection.head();
 7877        let multibuffer = self.buffer.read(cx).snapshot(cx);
 7878        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 7879        let excerpt_id = cursor.excerpt_id;
 7880
 7881        let show_in_menu = self.show_edit_predictions_in_menu();
 7882        let completions_menu_has_precedence = !show_in_menu
 7883            && (self.context_menu.borrow().is_some()
 7884                || (!self.completion_tasks.is_empty() && !self.has_active_edit_prediction()));
 7885
 7886        if completions_menu_has_precedence
 7887            || !offset_selection.is_empty()
 7888            || self
 7889                .active_edit_prediction
 7890                .as_ref()
 7891                .is_some_and(|completion| {
 7892                    let Some(invalidation_range) = completion.invalidation_range.as_ref() else {
 7893                        return false;
 7894                    };
 7895                    let invalidation_range = invalidation_range.to_offset(&multibuffer);
 7896                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 7897                    !invalidation_range.contains(&offset_selection.head())
 7898                })
 7899        {
 7900            self.discard_edit_prediction(false, cx);
 7901            return None;
 7902        }
 7903
 7904        self.take_active_edit_prediction(cx);
 7905        let Some(provider) = self.edit_prediction_provider() else {
 7906            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7907            return None;
 7908        };
 7909
 7910        let (buffer, cursor_buffer_position) =
 7911            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7912
 7913        self.edit_prediction_settings =
 7914            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7915
 7916        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 7917
 7918        if self.edit_prediction_indent_conflict {
 7919            let cursor_point = cursor.to_point(&multibuffer);
 7920
 7921            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 7922
 7923            if let Some((_, indent)) = indents.iter().next()
 7924                && indent.len == cursor_point.column
 7925            {
 7926                self.edit_prediction_indent_conflict = false;
 7927            }
 7928        }
 7929
 7930        let edit_prediction = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 7931
 7932        let (completion_id, edits, edit_preview) = match edit_prediction {
 7933            edit_prediction::EditPrediction::Local {
 7934                id,
 7935                edits,
 7936                edit_preview,
 7937            } => (id, edits, edit_preview),
 7938            edit_prediction::EditPrediction::Jump {
 7939                id,
 7940                snapshot,
 7941                target,
 7942            } => {
 7943                self.stale_edit_prediction_in_menu = None;
 7944                self.active_edit_prediction = Some(EditPredictionState {
 7945                    inlay_ids: vec![],
 7946                    completion: EditPrediction::MoveOutside { snapshot, target },
 7947                    completion_id: id,
 7948                    invalidation_range: None,
 7949                });
 7950                cx.notify();
 7951                return Some(());
 7952            }
 7953        };
 7954
 7955        let edits = edits
 7956            .into_iter()
 7957            .flat_map(|(range, new_text)| {
 7958                Some((
 7959                    multibuffer.anchor_range_in_excerpt(excerpt_id, range)?,
 7960                    new_text,
 7961                ))
 7962            })
 7963            .collect::<Vec<_>>();
 7964        if edits.is_empty() {
 7965            return None;
 7966        }
 7967
 7968        let first_edit_start = edits.first().unwrap().0.start;
 7969        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 7970        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 7971
 7972        let last_edit_end = edits.last().unwrap().0.end;
 7973        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 7974        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 7975
 7976        let cursor_row = cursor.to_point(&multibuffer).row;
 7977
 7978        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 7979
 7980        let mut inlay_ids = Vec::new();
 7981        let invalidation_row_range;
 7982        let move_invalidation_row_range = if cursor_row < edit_start_row {
 7983            Some(cursor_row..edit_end_row)
 7984        } else if cursor_row > edit_end_row {
 7985            Some(edit_start_row..cursor_row)
 7986        } else {
 7987            None
 7988        };
 7989        let supports_jump = self
 7990            .edit_prediction_provider
 7991            .as_ref()
 7992            .map(|provider| provider.provider.supports_jump_to_edit())
 7993            .unwrap_or(true);
 7994
 7995        let is_move = supports_jump
 7996            && (move_invalidation_row_range.is_some() || self.edit_predictions_hidden_for_vim_mode);
 7997        let completion = if is_move {
 7998            invalidation_row_range =
 7999                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 8000            let target = first_edit_start;
 8001            EditPrediction::MoveWithin { target, snapshot }
 8002        } else {
 8003            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 8004                && !self.edit_predictions_hidden_for_vim_mode;
 8005
 8006            if show_completions_in_buffer {
 8007                if edits
 8008                    .iter()
 8009                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 8010                {
 8011                    let mut inlays = Vec::new();
 8012                    for (range, new_text) in &edits {
 8013                        let inlay = Inlay::edit_prediction(
 8014                            post_inc(&mut self.next_inlay_id),
 8015                            range.start,
 8016                            new_text.as_ref(),
 8017                        );
 8018                        inlay_ids.push(inlay.id);
 8019                        inlays.push(inlay);
 8020                    }
 8021
 8022                    self.splice_inlays(&[], inlays, cx);
 8023                } else {
 8024                    let background_color = cx.theme().status().deleted_background;
 8025                    self.highlight_text::<EditPredictionHighlight>(
 8026                        edits.iter().map(|(range, _)| range.clone()).collect(),
 8027                        HighlightStyle {
 8028                            background_color: Some(background_color),
 8029                            ..Default::default()
 8030                        },
 8031                        cx,
 8032                    );
 8033                }
 8034            }
 8035
 8036            invalidation_row_range = edit_start_row..edit_end_row;
 8037
 8038            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 8039                if provider.show_tab_accept_marker() {
 8040                    EditDisplayMode::TabAccept
 8041                } else {
 8042                    EditDisplayMode::Inline
 8043                }
 8044            } else {
 8045                EditDisplayMode::DiffPopover
 8046            };
 8047
 8048            EditPrediction::Edit {
 8049                edits,
 8050                edit_preview,
 8051                display_mode,
 8052                snapshot,
 8053            }
 8054        };
 8055
 8056        let invalidation_range = multibuffer
 8057            .anchor_before(Point::new(invalidation_row_range.start, 0))
 8058            ..multibuffer.anchor_after(Point::new(
 8059                invalidation_row_range.end,
 8060                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 8061            ));
 8062
 8063        self.stale_edit_prediction_in_menu = None;
 8064        self.active_edit_prediction = Some(EditPredictionState {
 8065            inlay_ids,
 8066            completion,
 8067            completion_id,
 8068            invalidation_range: Some(invalidation_range),
 8069        });
 8070
 8071        cx.notify();
 8072
 8073        Some(())
 8074    }
 8075
 8076    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn EditPredictionProviderHandle>> {
 8077        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 8078    }
 8079
 8080    fn clear_tasks(&mut self) {
 8081        self.tasks.clear()
 8082    }
 8083
 8084    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 8085        if self.tasks.insert(key, value).is_some() {
 8086            // This case should hopefully be rare, but just in case...
 8087            log::error!(
 8088                "multiple different run targets found on a single line, only the last target will be rendered"
 8089            )
 8090        }
 8091    }
 8092
 8093    /// Get all display points of breakpoints that will be rendered within editor
 8094    ///
 8095    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 8096    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 8097    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 8098    fn active_breakpoints(
 8099        &self,
 8100        range: Range<DisplayRow>,
 8101        window: &mut Window,
 8102        cx: &mut Context<Self>,
 8103    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 8104        let mut breakpoint_display_points = HashMap::default();
 8105
 8106        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 8107            return breakpoint_display_points;
 8108        };
 8109
 8110        let snapshot = self.snapshot(window, cx);
 8111
 8112        let multi_buffer_snapshot = snapshot.buffer_snapshot();
 8113        let Some(project) = self.project() else {
 8114            return breakpoint_display_points;
 8115        };
 8116
 8117        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 8118            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 8119
 8120        for (buffer_snapshot, range, excerpt_id) in
 8121            multi_buffer_snapshot.range_to_buffer_ranges(range)
 8122        {
 8123            let Some(buffer) = project
 8124                .read(cx)
 8125                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 8126            else {
 8127                continue;
 8128            };
 8129            let breakpoints = breakpoint_store.read(cx).breakpoints(
 8130                &buffer,
 8131                Some(
 8132                    buffer_snapshot.anchor_before(range.start)
 8133                        ..buffer_snapshot.anchor_after(range.end),
 8134                ),
 8135                buffer_snapshot,
 8136                cx,
 8137            );
 8138            for (breakpoint, state) in breakpoints {
 8139                let multi_buffer_anchor =
 8140                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 8141                let position = multi_buffer_anchor
 8142                    .to_point(&multi_buffer_snapshot)
 8143                    .to_display_point(&snapshot);
 8144
 8145                breakpoint_display_points.insert(
 8146                    position.row(),
 8147                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 8148                );
 8149            }
 8150        }
 8151
 8152        breakpoint_display_points
 8153    }
 8154
 8155    fn breakpoint_context_menu(
 8156        &self,
 8157        anchor: Anchor,
 8158        window: &mut Window,
 8159        cx: &mut Context<Self>,
 8160    ) -> Entity<ui::ContextMenu> {
 8161        let weak_editor = cx.weak_entity();
 8162        let focus_handle = self.focus_handle(cx);
 8163
 8164        let row = self
 8165            .buffer
 8166            .read(cx)
 8167            .snapshot(cx)
 8168            .summary_for_anchor::<Point>(&anchor)
 8169            .row;
 8170
 8171        let breakpoint = self
 8172            .breakpoint_at_row(row, window, cx)
 8173            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 8174
 8175        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 8176            "Edit Log Breakpoint"
 8177        } else {
 8178            "Set Log Breakpoint"
 8179        };
 8180
 8181        let condition_breakpoint_msg = if breakpoint
 8182            .as_ref()
 8183            .is_some_and(|bp| bp.1.condition.is_some())
 8184        {
 8185            "Edit Condition Breakpoint"
 8186        } else {
 8187            "Set Condition Breakpoint"
 8188        };
 8189
 8190        let hit_condition_breakpoint_msg = if breakpoint
 8191            .as_ref()
 8192            .is_some_and(|bp| bp.1.hit_condition.is_some())
 8193        {
 8194            "Edit Hit Condition Breakpoint"
 8195        } else {
 8196            "Set Hit Condition Breakpoint"
 8197        };
 8198
 8199        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 8200            "Unset Breakpoint"
 8201        } else {
 8202            "Set Breakpoint"
 8203        };
 8204
 8205        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 8206
 8207        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 8208            BreakpointState::Enabled => Some("Disable"),
 8209            BreakpointState::Disabled => Some("Enable"),
 8210        });
 8211
 8212        let (anchor, breakpoint) =
 8213            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 8214
 8215        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 8216            menu.on_blur_subscription(Subscription::new(|| {}))
 8217                .context(focus_handle)
 8218                .when(run_to_cursor, |this| {
 8219                    let weak_editor = weak_editor.clone();
 8220                    this.entry("Run to cursor", None, move |window, cx| {
 8221                        weak_editor
 8222                            .update(cx, |editor, cx| {
 8223                                editor.change_selections(
 8224                                    SelectionEffects::no_scroll(),
 8225                                    window,
 8226                                    cx,
 8227                                    |s| s.select_ranges([Point::new(row, 0)..Point::new(row, 0)]),
 8228                                );
 8229                            })
 8230                            .ok();
 8231
 8232                        window.dispatch_action(Box::new(RunToCursor), cx);
 8233                    })
 8234                    .separator()
 8235                })
 8236                .when_some(toggle_state_msg, |this, msg| {
 8237                    this.entry(msg, None, {
 8238                        let weak_editor = weak_editor.clone();
 8239                        let breakpoint = breakpoint.clone();
 8240                        move |_window, cx| {
 8241                            weak_editor
 8242                                .update(cx, |this, cx| {
 8243                                    this.edit_breakpoint_at_anchor(
 8244                                        anchor,
 8245                                        breakpoint.as_ref().clone(),
 8246                                        BreakpointEditAction::InvertState,
 8247                                        cx,
 8248                                    );
 8249                                })
 8250                                .log_err();
 8251                        }
 8252                    })
 8253                })
 8254                .entry(set_breakpoint_msg, None, {
 8255                    let weak_editor = weak_editor.clone();
 8256                    let breakpoint = breakpoint.clone();
 8257                    move |_window, cx| {
 8258                        weak_editor
 8259                            .update(cx, |this, cx| {
 8260                                this.edit_breakpoint_at_anchor(
 8261                                    anchor,
 8262                                    breakpoint.as_ref().clone(),
 8263                                    BreakpointEditAction::Toggle,
 8264                                    cx,
 8265                                );
 8266                            })
 8267                            .log_err();
 8268                    }
 8269                })
 8270                .entry(log_breakpoint_msg, None, {
 8271                    let breakpoint = breakpoint.clone();
 8272                    let weak_editor = weak_editor.clone();
 8273                    move |window, cx| {
 8274                        weak_editor
 8275                            .update(cx, |this, cx| {
 8276                                this.add_edit_breakpoint_block(
 8277                                    anchor,
 8278                                    breakpoint.as_ref(),
 8279                                    BreakpointPromptEditAction::Log,
 8280                                    window,
 8281                                    cx,
 8282                                );
 8283                            })
 8284                            .log_err();
 8285                    }
 8286                })
 8287                .entry(condition_breakpoint_msg, None, {
 8288                    let breakpoint = breakpoint.clone();
 8289                    let weak_editor = weak_editor.clone();
 8290                    move |window, cx| {
 8291                        weak_editor
 8292                            .update(cx, |this, cx| {
 8293                                this.add_edit_breakpoint_block(
 8294                                    anchor,
 8295                                    breakpoint.as_ref(),
 8296                                    BreakpointPromptEditAction::Condition,
 8297                                    window,
 8298                                    cx,
 8299                                );
 8300                            })
 8301                            .log_err();
 8302                    }
 8303                })
 8304                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 8305                    weak_editor
 8306                        .update(cx, |this, cx| {
 8307                            this.add_edit_breakpoint_block(
 8308                                anchor,
 8309                                breakpoint.as_ref(),
 8310                                BreakpointPromptEditAction::HitCondition,
 8311                                window,
 8312                                cx,
 8313                            );
 8314                        })
 8315                        .log_err();
 8316                })
 8317        })
 8318    }
 8319
 8320    fn render_breakpoint(
 8321        &self,
 8322        position: Anchor,
 8323        row: DisplayRow,
 8324        breakpoint: &Breakpoint,
 8325        state: Option<BreakpointSessionState>,
 8326        cx: &mut Context<Self>,
 8327    ) -> IconButton {
 8328        let is_rejected = state.is_some_and(|s| !s.verified);
 8329        // Is it a breakpoint that shows up when hovering over gutter?
 8330        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 8331            (false, false),
 8332            |PhantomBreakpointIndicator {
 8333                 is_active,
 8334                 display_row,
 8335                 collides_with_existing_breakpoint,
 8336             }| {
 8337                (
 8338                    is_active && display_row == row,
 8339                    collides_with_existing_breakpoint,
 8340                )
 8341            },
 8342        );
 8343
 8344        let (color, icon) = {
 8345            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 8346                (false, false) => ui::IconName::DebugBreakpoint,
 8347                (true, false) => ui::IconName::DebugLogBreakpoint,
 8348                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 8349                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 8350            };
 8351
 8352            let color = if is_phantom {
 8353                Color::Hint
 8354            } else if is_rejected {
 8355                Color::Disabled
 8356            } else {
 8357                Color::Debugger
 8358            };
 8359
 8360            (color, icon)
 8361        };
 8362
 8363        let breakpoint = Arc::from(breakpoint.clone());
 8364
 8365        let alt_as_text = gpui::Keystroke {
 8366            modifiers: Modifiers::secondary_key(),
 8367            ..Default::default()
 8368        };
 8369        let primary_action_text = if breakpoint.is_disabled() {
 8370            "Enable breakpoint"
 8371        } else if is_phantom && !collides_with_existing {
 8372            "Set breakpoint"
 8373        } else {
 8374            "Unset breakpoint"
 8375        };
 8376        let focus_handle = self.focus_handle.clone();
 8377
 8378        let meta = if is_rejected {
 8379            SharedString::from("No executable code is associated with this line.")
 8380        } else if collides_with_existing && !breakpoint.is_disabled() {
 8381            SharedString::from(format!(
 8382                "{alt_as_text}-click to disable,\nright-click for more options."
 8383            ))
 8384        } else {
 8385            SharedString::from("Right-click for more options.")
 8386        };
 8387        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 8388            .icon_size(IconSize::XSmall)
 8389            .size(ui::ButtonSize::None)
 8390            .when(is_rejected, |this| {
 8391                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 8392            })
 8393            .icon_color(color)
 8394            .style(ButtonStyle::Transparent)
 8395            .on_click(cx.listener({
 8396                move |editor, event: &ClickEvent, window, cx| {
 8397                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 8398                        BreakpointEditAction::InvertState
 8399                    } else {
 8400                        BreakpointEditAction::Toggle
 8401                    };
 8402
 8403                    window.focus(&editor.focus_handle(cx));
 8404                    editor.edit_breakpoint_at_anchor(
 8405                        position,
 8406                        breakpoint.as_ref().clone(),
 8407                        edit_action,
 8408                        cx,
 8409                    );
 8410                }
 8411            }))
 8412            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8413                editor.set_breakpoint_context_menu(
 8414                    row,
 8415                    Some(position),
 8416                    event.position(),
 8417                    window,
 8418                    cx,
 8419                );
 8420            }))
 8421            .tooltip(move |_window, cx| {
 8422                Tooltip::with_meta_in(
 8423                    primary_action_text,
 8424                    Some(&ToggleBreakpoint),
 8425                    meta.clone(),
 8426                    &focus_handle,
 8427                    cx,
 8428                )
 8429            })
 8430    }
 8431
 8432    fn build_tasks_context(
 8433        project: &Entity<Project>,
 8434        buffer: &Entity<Buffer>,
 8435        buffer_row: u32,
 8436        tasks: &Arc<RunnableTasks>,
 8437        cx: &mut Context<Self>,
 8438    ) -> Task<Option<task::TaskContext>> {
 8439        let position = Point::new(buffer_row, tasks.column);
 8440        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 8441        let location = Location {
 8442            buffer: buffer.clone(),
 8443            range: range_start..range_start,
 8444        };
 8445        // Fill in the environmental variables from the tree-sitter captures
 8446        let mut captured_task_variables = TaskVariables::default();
 8447        for (capture_name, value) in tasks.extra_variables.clone() {
 8448            captured_task_variables.insert(
 8449                task::VariableName::Custom(capture_name.into()),
 8450                value.clone(),
 8451            );
 8452        }
 8453        project.update(cx, |project, cx| {
 8454            project.task_store().update(cx, |task_store, cx| {
 8455                task_store.task_context_for_location(captured_task_variables, location, cx)
 8456            })
 8457        })
 8458    }
 8459
 8460    pub fn spawn_nearest_task(
 8461        &mut self,
 8462        action: &SpawnNearestTask,
 8463        window: &mut Window,
 8464        cx: &mut Context<Self>,
 8465    ) {
 8466        let Some((workspace, _)) = self.workspace.clone() else {
 8467            return;
 8468        };
 8469        let Some(project) = self.project.clone() else {
 8470            return;
 8471        };
 8472
 8473        // Try to find a closest, enclosing node using tree-sitter that has a task
 8474        let Some((buffer, buffer_row, tasks)) = self
 8475            .find_enclosing_node_task(cx)
 8476            // Or find the task that's closest in row-distance.
 8477            .or_else(|| self.find_closest_task(cx))
 8478        else {
 8479            return;
 8480        };
 8481
 8482        let reveal_strategy = action.reveal;
 8483        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 8484        cx.spawn_in(window, async move |_, cx| {
 8485            let context = task_context.await?;
 8486            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 8487
 8488            let resolved = &mut resolved_task.resolved;
 8489            resolved.reveal = reveal_strategy;
 8490
 8491            workspace
 8492                .update_in(cx, |workspace, window, cx| {
 8493                    workspace.schedule_resolved_task(
 8494                        task_source_kind,
 8495                        resolved_task,
 8496                        false,
 8497                        window,
 8498                        cx,
 8499                    );
 8500                })
 8501                .ok()
 8502        })
 8503        .detach();
 8504    }
 8505
 8506    fn find_closest_task(
 8507        &mut self,
 8508        cx: &mut Context<Self>,
 8509    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8510        let cursor_row = self
 8511            .selections
 8512            .newest_adjusted(&self.display_snapshot(cx))
 8513            .head()
 8514            .row;
 8515
 8516        let ((buffer_id, row), tasks) = self
 8517            .tasks
 8518            .iter()
 8519            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 8520
 8521        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 8522        let tasks = Arc::new(tasks.to_owned());
 8523        Some((buffer, *row, tasks))
 8524    }
 8525
 8526    fn find_enclosing_node_task(
 8527        &mut self,
 8528        cx: &mut Context<Self>,
 8529    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8530        let snapshot = self.buffer.read(cx).snapshot(cx);
 8531        let offset = self
 8532            .selections
 8533            .newest::<usize>(&self.display_snapshot(cx))
 8534            .head();
 8535        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 8536        let buffer_id = excerpt.buffer().remote_id();
 8537
 8538        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 8539        let mut cursor = layer.node().walk();
 8540
 8541        while cursor.goto_first_child_for_byte(offset).is_some() {
 8542            if cursor.node().end_byte() == offset {
 8543                cursor.goto_next_sibling();
 8544            }
 8545        }
 8546
 8547        // Ascend to the smallest ancestor that contains the range and has a task.
 8548        loop {
 8549            let node = cursor.node();
 8550            let node_range = node.byte_range();
 8551            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 8552
 8553            // Check if this node contains our offset
 8554            if node_range.start <= offset && node_range.end >= offset {
 8555                // If it contains offset, check for task
 8556                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 8557                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 8558                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 8559                }
 8560            }
 8561
 8562            if !cursor.goto_parent() {
 8563                break;
 8564            }
 8565        }
 8566        None
 8567    }
 8568
 8569    fn render_run_indicator(
 8570        &self,
 8571        _style: &EditorStyle,
 8572        is_active: bool,
 8573        row: DisplayRow,
 8574        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 8575        cx: &mut Context<Self>,
 8576    ) -> IconButton {
 8577        let color = Color::Muted;
 8578        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 8579
 8580        IconButton::new(
 8581            ("run_indicator", row.0 as usize),
 8582            ui::IconName::PlayOutlined,
 8583        )
 8584        .shape(ui::IconButtonShape::Square)
 8585        .icon_size(IconSize::XSmall)
 8586        .icon_color(color)
 8587        .toggle_state(is_active)
 8588        .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 8589            let quick_launch = match e {
 8590                ClickEvent::Keyboard(_) => true,
 8591                ClickEvent::Mouse(e) => e.down.button == MouseButton::Left,
 8592            };
 8593
 8594            window.focus(&editor.focus_handle(cx));
 8595            editor.toggle_code_actions(
 8596                &ToggleCodeActions {
 8597                    deployed_from: Some(CodeActionSource::RunMenu(row)),
 8598                    quick_launch,
 8599                },
 8600                window,
 8601                cx,
 8602            );
 8603        }))
 8604        .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8605            editor.set_breakpoint_context_menu(row, position, event.position(), window, cx);
 8606        }))
 8607    }
 8608
 8609    pub fn context_menu_visible(&self) -> bool {
 8610        !self.edit_prediction_preview_is_active()
 8611            && self
 8612                .context_menu
 8613                .borrow()
 8614                .as_ref()
 8615                .is_some_and(|menu| menu.visible())
 8616    }
 8617
 8618    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 8619        self.context_menu
 8620            .borrow()
 8621            .as_ref()
 8622            .map(|menu| menu.origin())
 8623    }
 8624
 8625    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 8626        self.context_menu_options = Some(options);
 8627    }
 8628
 8629    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = px(24.);
 8630    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = px(2.);
 8631
 8632    fn render_edit_prediction_popover(
 8633        &mut self,
 8634        text_bounds: &Bounds<Pixels>,
 8635        content_origin: gpui::Point<Pixels>,
 8636        right_margin: Pixels,
 8637        editor_snapshot: &EditorSnapshot,
 8638        visible_row_range: Range<DisplayRow>,
 8639        scroll_top: ScrollOffset,
 8640        scroll_bottom: ScrollOffset,
 8641        line_layouts: &[LineWithInvisibles],
 8642        line_height: Pixels,
 8643        scroll_position: gpui::Point<ScrollOffset>,
 8644        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8645        newest_selection_head: Option<DisplayPoint>,
 8646        editor_width: Pixels,
 8647        style: &EditorStyle,
 8648        window: &mut Window,
 8649        cx: &mut App,
 8650    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8651        if self.mode().is_minimap() {
 8652            return None;
 8653        }
 8654        let active_edit_prediction = self.active_edit_prediction.as_ref()?;
 8655
 8656        if self.edit_prediction_visible_in_cursor_popover(true) {
 8657            return None;
 8658        }
 8659
 8660        match &active_edit_prediction.completion {
 8661            EditPrediction::MoveWithin { target, .. } => {
 8662                let target_display_point = target.to_display_point(editor_snapshot);
 8663
 8664                if self.edit_prediction_requires_modifier() {
 8665                    if !self.edit_prediction_preview_is_active() {
 8666                        return None;
 8667                    }
 8668
 8669                    self.render_edit_prediction_modifier_jump_popover(
 8670                        text_bounds,
 8671                        content_origin,
 8672                        visible_row_range,
 8673                        line_layouts,
 8674                        line_height,
 8675                        scroll_pixel_position,
 8676                        newest_selection_head,
 8677                        target_display_point,
 8678                        window,
 8679                        cx,
 8680                    )
 8681                } else {
 8682                    self.render_edit_prediction_eager_jump_popover(
 8683                        text_bounds,
 8684                        content_origin,
 8685                        editor_snapshot,
 8686                        visible_row_range,
 8687                        scroll_top,
 8688                        scroll_bottom,
 8689                        line_height,
 8690                        scroll_pixel_position,
 8691                        target_display_point,
 8692                        editor_width,
 8693                        window,
 8694                        cx,
 8695                    )
 8696                }
 8697            }
 8698            EditPrediction::Edit {
 8699                display_mode: EditDisplayMode::Inline,
 8700                ..
 8701            } => None,
 8702            EditPrediction::Edit {
 8703                display_mode: EditDisplayMode::TabAccept,
 8704                edits,
 8705                ..
 8706            } => {
 8707                let range = &edits.first()?.0;
 8708                let target_display_point = range.end.to_display_point(editor_snapshot);
 8709
 8710                self.render_edit_prediction_end_of_line_popover(
 8711                    "Accept",
 8712                    editor_snapshot,
 8713                    visible_row_range,
 8714                    target_display_point,
 8715                    line_height,
 8716                    scroll_pixel_position,
 8717                    content_origin,
 8718                    editor_width,
 8719                    window,
 8720                    cx,
 8721                )
 8722            }
 8723            EditPrediction::Edit {
 8724                edits,
 8725                edit_preview,
 8726                display_mode: EditDisplayMode::DiffPopover,
 8727                snapshot,
 8728            } => self.render_edit_prediction_diff_popover(
 8729                text_bounds,
 8730                content_origin,
 8731                right_margin,
 8732                editor_snapshot,
 8733                visible_row_range,
 8734                line_layouts,
 8735                line_height,
 8736                scroll_position,
 8737                scroll_pixel_position,
 8738                newest_selection_head,
 8739                editor_width,
 8740                style,
 8741                edits,
 8742                edit_preview,
 8743                snapshot,
 8744                window,
 8745                cx,
 8746            ),
 8747            EditPrediction::MoveOutside { snapshot, .. } => {
 8748                let file_name = snapshot
 8749                    .file()
 8750                    .map(|file| file.file_name(cx))
 8751                    .unwrap_or("untitled");
 8752                let mut element = self
 8753                    .render_edit_prediction_line_popover(
 8754                        format!("Jump to {file_name}"),
 8755                        Some(IconName::ZedPredict),
 8756                        window,
 8757                        cx,
 8758                    )
 8759                    .into_any();
 8760
 8761                let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8762                let origin_x = text_bounds.size.width / 2. - size.width / 2.;
 8763                let origin_y = text_bounds.size.height - size.height - px(30.);
 8764                let origin = text_bounds.origin + gpui::Point::new(origin_x, origin_y);
 8765                element.prepaint_at(origin, window, cx);
 8766
 8767                Some((element, origin))
 8768            }
 8769        }
 8770    }
 8771
 8772    fn render_edit_prediction_modifier_jump_popover(
 8773        &mut self,
 8774        text_bounds: &Bounds<Pixels>,
 8775        content_origin: gpui::Point<Pixels>,
 8776        visible_row_range: Range<DisplayRow>,
 8777        line_layouts: &[LineWithInvisibles],
 8778        line_height: Pixels,
 8779        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8780        newest_selection_head: Option<DisplayPoint>,
 8781        target_display_point: DisplayPoint,
 8782        window: &mut Window,
 8783        cx: &mut App,
 8784    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8785        let scrolled_content_origin =
 8786            content_origin - gpui::Point::new(scroll_pixel_position.x.into(), Pixels::ZERO);
 8787
 8788        const SCROLL_PADDING_Y: Pixels = px(12.);
 8789
 8790        if target_display_point.row() < visible_row_range.start {
 8791            return self.render_edit_prediction_scroll_popover(
 8792                |_| SCROLL_PADDING_Y,
 8793                IconName::ArrowUp,
 8794                visible_row_range,
 8795                line_layouts,
 8796                newest_selection_head,
 8797                scrolled_content_origin,
 8798                window,
 8799                cx,
 8800            );
 8801        } else if target_display_point.row() >= visible_row_range.end {
 8802            return self.render_edit_prediction_scroll_popover(
 8803                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 8804                IconName::ArrowDown,
 8805                visible_row_range,
 8806                line_layouts,
 8807                newest_selection_head,
 8808                scrolled_content_origin,
 8809                window,
 8810                cx,
 8811            );
 8812        }
 8813
 8814        const POLE_WIDTH: Pixels = px(2.);
 8815
 8816        let line_layout =
 8817            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 8818        let target_column = target_display_point.column() as usize;
 8819
 8820        let target_x = line_layout.x_for_index(target_column);
 8821        let target_y = (target_display_point.row().as_f64() * f64::from(line_height))
 8822            - scroll_pixel_position.y;
 8823
 8824        let flag_on_right = target_x < text_bounds.size.width / 2.;
 8825
 8826        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 8827        border_color.l += 0.001;
 8828
 8829        let mut element = v_flex()
 8830            .items_end()
 8831            .when(flag_on_right, |el| el.items_start())
 8832            .child(if flag_on_right {
 8833                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 8834                    .rounded_bl(px(0.))
 8835                    .rounded_tl(px(0.))
 8836                    .border_l_2()
 8837                    .border_color(border_color)
 8838            } else {
 8839                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 8840                    .rounded_br(px(0.))
 8841                    .rounded_tr(px(0.))
 8842                    .border_r_2()
 8843                    .border_color(border_color)
 8844            })
 8845            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 8846            .into_any();
 8847
 8848        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8849
 8850        let mut origin = scrolled_content_origin + point(target_x, target_y.into())
 8851            - point(
 8852                if flag_on_right {
 8853                    POLE_WIDTH
 8854                } else {
 8855                    size.width - POLE_WIDTH
 8856                },
 8857                size.height - line_height,
 8858            );
 8859
 8860        origin.x = origin.x.max(content_origin.x);
 8861
 8862        element.prepaint_at(origin, window, cx);
 8863
 8864        Some((element, origin))
 8865    }
 8866
 8867    fn render_edit_prediction_scroll_popover(
 8868        &mut self,
 8869        to_y: impl Fn(Size<Pixels>) -> Pixels,
 8870        scroll_icon: IconName,
 8871        visible_row_range: Range<DisplayRow>,
 8872        line_layouts: &[LineWithInvisibles],
 8873        newest_selection_head: Option<DisplayPoint>,
 8874        scrolled_content_origin: gpui::Point<Pixels>,
 8875        window: &mut Window,
 8876        cx: &mut App,
 8877    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8878        let mut element = self
 8879            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)
 8880            .into_any();
 8881
 8882        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8883
 8884        let cursor = newest_selection_head?;
 8885        let cursor_row_layout =
 8886            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 8887        let cursor_column = cursor.column() as usize;
 8888
 8889        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 8890
 8891        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 8892
 8893        element.prepaint_at(origin, window, cx);
 8894        Some((element, origin))
 8895    }
 8896
 8897    fn render_edit_prediction_eager_jump_popover(
 8898        &mut self,
 8899        text_bounds: &Bounds<Pixels>,
 8900        content_origin: gpui::Point<Pixels>,
 8901        editor_snapshot: &EditorSnapshot,
 8902        visible_row_range: Range<DisplayRow>,
 8903        scroll_top: ScrollOffset,
 8904        scroll_bottom: ScrollOffset,
 8905        line_height: Pixels,
 8906        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8907        target_display_point: DisplayPoint,
 8908        editor_width: Pixels,
 8909        window: &mut Window,
 8910        cx: &mut App,
 8911    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8912        if target_display_point.row().as_f64() < scroll_top {
 8913            let mut element = self
 8914                .render_edit_prediction_line_popover(
 8915                    "Jump to Edit",
 8916                    Some(IconName::ArrowUp),
 8917                    window,
 8918                    cx,
 8919                )
 8920                .into_any();
 8921
 8922            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8923            let offset = point(
 8924                (text_bounds.size.width - size.width) / 2.,
 8925                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8926            );
 8927
 8928            let origin = text_bounds.origin + offset;
 8929            element.prepaint_at(origin, window, cx);
 8930            Some((element, origin))
 8931        } else if (target_display_point.row().as_f64() + 1.) > scroll_bottom {
 8932            let mut element = self
 8933                .render_edit_prediction_line_popover(
 8934                    "Jump to Edit",
 8935                    Some(IconName::ArrowDown),
 8936                    window,
 8937                    cx,
 8938                )
 8939                .into_any();
 8940
 8941            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8942            let offset = point(
 8943                (text_bounds.size.width - size.width) / 2.,
 8944                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8945            );
 8946
 8947            let origin = text_bounds.origin + offset;
 8948            element.prepaint_at(origin, window, cx);
 8949            Some((element, origin))
 8950        } else {
 8951            self.render_edit_prediction_end_of_line_popover(
 8952                "Jump to Edit",
 8953                editor_snapshot,
 8954                visible_row_range,
 8955                target_display_point,
 8956                line_height,
 8957                scroll_pixel_position,
 8958                content_origin,
 8959                editor_width,
 8960                window,
 8961                cx,
 8962            )
 8963        }
 8964    }
 8965
 8966    fn render_edit_prediction_end_of_line_popover(
 8967        self: &mut Editor,
 8968        label: &'static str,
 8969        editor_snapshot: &EditorSnapshot,
 8970        visible_row_range: Range<DisplayRow>,
 8971        target_display_point: DisplayPoint,
 8972        line_height: Pixels,
 8973        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8974        content_origin: gpui::Point<Pixels>,
 8975        editor_width: Pixels,
 8976        window: &mut Window,
 8977        cx: &mut App,
 8978    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8979        let target_line_end = DisplayPoint::new(
 8980            target_display_point.row(),
 8981            editor_snapshot.line_len(target_display_point.row()),
 8982        );
 8983
 8984        let mut element = self
 8985            .render_edit_prediction_line_popover(label, None, window, cx)
 8986            .into_any();
 8987
 8988        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8989
 8990        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 8991
 8992        let start_point = content_origin - point(scroll_pixel_position.x.into(), Pixels::ZERO);
 8993        let mut origin = start_point
 8994            + line_origin
 8995            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 8996        origin.x = origin.x.max(content_origin.x);
 8997
 8998        let max_x = content_origin.x + editor_width - size.width;
 8999
 9000        if origin.x > max_x {
 9001            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 9002
 9003            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 9004                origin.y += offset;
 9005                IconName::ArrowUp
 9006            } else {
 9007                origin.y -= offset;
 9008                IconName::ArrowDown
 9009            };
 9010
 9011            element = self
 9012                .render_edit_prediction_line_popover(label, Some(icon), window, cx)
 9013                .into_any();
 9014
 9015            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9016
 9017            origin.x = content_origin.x + editor_width - size.width - px(2.);
 9018        }
 9019
 9020        element.prepaint_at(origin, window, cx);
 9021        Some((element, origin))
 9022    }
 9023
 9024    fn render_edit_prediction_diff_popover(
 9025        self: &Editor,
 9026        text_bounds: &Bounds<Pixels>,
 9027        content_origin: gpui::Point<Pixels>,
 9028        right_margin: Pixels,
 9029        editor_snapshot: &EditorSnapshot,
 9030        visible_row_range: Range<DisplayRow>,
 9031        line_layouts: &[LineWithInvisibles],
 9032        line_height: Pixels,
 9033        scroll_position: gpui::Point<ScrollOffset>,
 9034        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9035        newest_selection_head: Option<DisplayPoint>,
 9036        editor_width: Pixels,
 9037        style: &EditorStyle,
 9038        edits: &Vec<(Range<Anchor>, Arc<str>)>,
 9039        edit_preview: &Option<language::EditPreview>,
 9040        snapshot: &language::BufferSnapshot,
 9041        window: &mut Window,
 9042        cx: &mut App,
 9043    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9044        let edit_start = edits
 9045            .first()
 9046            .unwrap()
 9047            .0
 9048            .start
 9049            .to_display_point(editor_snapshot);
 9050        let edit_end = edits
 9051            .last()
 9052            .unwrap()
 9053            .0
 9054            .end
 9055            .to_display_point(editor_snapshot);
 9056
 9057        let is_visible = visible_row_range.contains(&edit_start.row())
 9058            || visible_row_range.contains(&edit_end.row());
 9059        if !is_visible {
 9060            return None;
 9061        }
 9062
 9063        let highlighted_edits = if let Some(edit_preview) = edit_preview.as_ref() {
 9064            crate::edit_prediction_edit_text(snapshot, edits, edit_preview, false, cx)
 9065        } else {
 9066            // Fallback for providers without edit_preview
 9067            crate::edit_prediction_fallback_text(edits, cx)
 9068        };
 9069
 9070        let styled_text = highlighted_edits.to_styled_text(&style.text);
 9071        let line_count = highlighted_edits.text.lines().count();
 9072
 9073        const BORDER_WIDTH: Pixels = px(1.);
 9074
 9075        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9076        let has_keybind = keybind.is_some();
 9077
 9078        let mut element = h_flex()
 9079            .items_start()
 9080            .child(
 9081                h_flex()
 9082                    .bg(cx.theme().colors().editor_background)
 9083                    .border(BORDER_WIDTH)
 9084                    .shadow_xs()
 9085                    .border_color(cx.theme().colors().border)
 9086                    .rounded_l_lg()
 9087                    .when(line_count > 1, |el| el.rounded_br_lg())
 9088                    .pr_1()
 9089                    .child(styled_text),
 9090            )
 9091            .child(
 9092                h_flex()
 9093                    .h(line_height + BORDER_WIDTH * 2.)
 9094                    .px_1p5()
 9095                    .gap_1()
 9096                    // Workaround: For some reason, there's a gap if we don't do this
 9097                    .ml(-BORDER_WIDTH)
 9098                    .shadow(vec![gpui::BoxShadow {
 9099                        color: gpui::black().opacity(0.05),
 9100                        offset: point(px(1.), px(1.)),
 9101                        blur_radius: px(2.),
 9102                        spread_radius: px(0.),
 9103                    }])
 9104                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 9105                    .border(BORDER_WIDTH)
 9106                    .border_color(cx.theme().colors().border)
 9107                    .rounded_r_lg()
 9108                    .id("edit_prediction_diff_popover_keybind")
 9109                    .when(!has_keybind, |el| {
 9110                        let status_colors = cx.theme().status();
 9111
 9112                        el.bg(status_colors.error_background)
 9113                            .border_color(status_colors.error.opacity(0.6))
 9114                            .child(Icon::new(IconName::Info).color(Color::Error))
 9115                            .cursor_default()
 9116                            .hoverable_tooltip(move |_window, cx| {
 9117                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9118                            })
 9119                    })
 9120                    .children(keybind),
 9121            )
 9122            .into_any();
 9123
 9124        let longest_row =
 9125            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 9126        let longest_line_width = if visible_row_range.contains(&longest_row) {
 9127            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 9128        } else {
 9129            layout_line(
 9130                longest_row,
 9131                editor_snapshot,
 9132                style,
 9133                editor_width,
 9134                |_| false,
 9135                window,
 9136                cx,
 9137            )
 9138            .width
 9139        };
 9140
 9141        let viewport_bounds =
 9142            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 9143                right: -right_margin,
 9144                ..Default::default()
 9145            });
 9146
 9147        let x_after_longest = Pixels::from(
 9148            ScrollPixelOffset::from(
 9149                text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X,
 9150            ) - scroll_pixel_position.x,
 9151        );
 9152
 9153        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9154
 9155        // Fully visible if it can be displayed within the window (allow overlapping other
 9156        // panes). However, this is only allowed if the popover starts within text_bounds.
 9157        let can_position_to_the_right = x_after_longest < text_bounds.right()
 9158            && x_after_longest + element_bounds.width < viewport_bounds.right();
 9159
 9160        let mut origin = if can_position_to_the_right {
 9161            point(
 9162                x_after_longest,
 9163                text_bounds.origin.y
 9164                    + Pixels::from(
 9165                        edit_start.row().as_f64() * ScrollPixelOffset::from(line_height)
 9166                            - scroll_pixel_position.y,
 9167                    ),
 9168            )
 9169        } else {
 9170            let cursor_row = newest_selection_head.map(|head| head.row());
 9171            let above_edit = edit_start
 9172                .row()
 9173                .0
 9174                .checked_sub(line_count as u32)
 9175                .map(DisplayRow);
 9176            let below_edit = Some(edit_end.row() + 1);
 9177            let above_cursor =
 9178                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 9179            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 9180
 9181            // Place the edit popover adjacent to the edit if there is a location
 9182            // available that is onscreen and does not obscure the cursor. Otherwise,
 9183            // place it adjacent to the cursor.
 9184            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 9185                .into_iter()
 9186                .flatten()
 9187                .find(|&start_row| {
 9188                    let end_row = start_row + line_count as u32;
 9189                    visible_row_range.contains(&start_row)
 9190                        && visible_row_range.contains(&end_row)
 9191                        && cursor_row
 9192                            .is_none_or(|cursor_row| !((start_row..end_row).contains(&cursor_row)))
 9193                })?;
 9194
 9195            content_origin
 9196                + point(
 9197                    Pixels::from(-scroll_pixel_position.x),
 9198                    Pixels::from(
 9199                        (row_target.as_f64() - scroll_position.y) * f64::from(line_height),
 9200                    ),
 9201                )
 9202        };
 9203
 9204        origin.x -= BORDER_WIDTH;
 9205
 9206        window.defer_draw(element, origin, 1);
 9207
 9208        // Do not return an element, since it will already be drawn due to defer_draw.
 9209        None
 9210    }
 9211
 9212    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 9213        px(30.)
 9214    }
 9215
 9216    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 9217        if self.read_only(cx) {
 9218            cx.theme().players().read_only()
 9219        } else {
 9220            self.style.as_ref().unwrap().local_player
 9221        }
 9222    }
 9223
 9224    fn render_edit_prediction_accept_keybind(
 9225        &self,
 9226        window: &mut Window,
 9227        cx: &mut App,
 9228    ) -> Option<AnyElement> {
 9229        let accept_binding = self.accept_edit_prediction_keybind(false, window, cx);
 9230        let accept_keystroke = accept_binding.keystroke()?;
 9231
 9232        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9233
 9234        let modifiers_color = if *accept_keystroke.modifiers() == window.modifiers() {
 9235            Color::Accent
 9236        } else {
 9237            Color::Muted
 9238        };
 9239
 9240        h_flex()
 9241            .px_0p5()
 9242            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 9243            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9244            .text_size(TextSize::XSmall.rems(cx))
 9245            .child(h_flex().children(ui::render_modifiers(
 9246                accept_keystroke.modifiers(),
 9247                PlatformStyle::platform(),
 9248                Some(modifiers_color),
 9249                Some(IconSize::XSmall.rems().into()),
 9250                true,
 9251            )))
 9252            .when(is_platform_style_mac, |parent| {
 9253                parent.child(accept_keystroke.key().to_string())
 9254            })
 9255            .when(!is_platform_style_mac, |parent| {
 9256                parent.child(
 9257                    Key::new(
 9258                        util::capitalize(accept_keystroke.key()),
 9259                        Some(Color::Default),
 9260                    )
 9261                    .size(Some(IconSize::XSmall.rems().into())),
 9262                )
 9263            })
 9264            .into_any()
 9265            .into()
 9266    }
 9267
 9268    fn render_edit_prediction_line_popover(
 9269        &self,
 9270        label: impl Into<SharedString>,
 9271        icon: Option<IconName>,
 9272        window: &mut Window,
 9273        cx: &mut App,
 9274    ) -> Stateful<Div> {
 9275        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 9276
 9277        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9278        let has_keybind = keybind.is_some();
 9279
 9280        h_flex()
 9281            .id("ep-line-popover")
 9282            .py_0p5()
 9283            .pl_1()
 9284            .pr(padding_right)
 9285            .gap_1()
 9286            .rounded_md()
 9287            .border_1()
 9288            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9289            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9290            .shadow_xs()
 9291            .when(!has_keybind, |el| {
 9292                let status_colors = cx.theme().status();
 9293
 9294                el.bg(status_colors.error_background)
 9295                    .border_color(status_colors.error.opacity(0.6))
 9296                    .pl_2()
 9297                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9298                    .cursor_default()
 9299                    .hoverable_tooltip(move |_window, cx| {
 9300                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9301                    })
 9302            })
 9303            .children(keybind)
 9304            .child(
 9305                Label::new(label)
 9306                    .size(LabelSize::Small)
 9307                    .when(!has_keybind, |el| {
 9308                        el.color(cx.theme().status().error.into()).strikethrough()
 9309                    }),
 9310            )
 9311            .when(!has_keybind, |el| {
 9312                el.child(
 9313                    h_flex().ml_1().child(
 9314                        Icon::new(IconName::Info)
 9315                            .size(IconSize::Small)
 9316                            .color(cx.theme().status().error.into()),
 9317                    ),
 9318                )
 9319            })
 9320            .when_some(icon, |element, icon| {
 9321                element.child(
 9322                    div()
 9323                        .mt(px(1.5))
 9324                        .child(Icon::new(icon).size(IconSize::Small)),
 9325                )
 9326            })
 9327    }
 9328
 9329    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 9330        let accent_color = cx.theme().colors().text_accent;
 9331        let editor_bg_color = cx.theme().colors().editor_background;
 9332        editor_bg_color.blend(accent_color.opacity(0.1))
 9333    }
 9334
 9335    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 9336        let accent_color = cx.theme().colors().text_accent;
 9337        let editor_bg_color = cx.theme().colors().editor_background;
 9338        editor_bg_color.blend(accent_color.opacity(0.6))
 9339    }
 9340    fn get_prediction_provider_icon_name(
 9341        provider: &Option<RegisteredEditPredictionProvider>,
 9342    ) -> IconName {
 9343        match provider {
 9344            Some(provider) => match provider.provider.name() {
 9345                "copilot" => IconName::Copilot,
 9346                "supermaven" => IconName::Supermaven,
 9347                _ => IconName::ZedPredict,
 9348            },
 9349            None => IconName::ZedPredict,
 9350        }
 9351    }
 9352
 9353    fn render_edit_prediction_cursor_popover(
 9354        &self,
 9355        min_width: Pixels,
 9356        max_width: Pixels,
 9357        cursor_point: Point,
 9358        style: &EditorStyle,
 9359        accept_keystroke: Option<&gpui::KeybindingKeystroke>,
 9360        _window: &Window,
 9361        cx: &mut Context<Editor>,
 9362    ) -> Option<AnyElement> {
 9363        let provider = self.edit_prediction_provider.as_ref()?;
 9364        let provider_icon = Self::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9365
 9366        let is_refreshing = provider.provider.is_refreshing(cx);
 9367
 9368        fn pending_completion_container(icon: IconName) -> Div {
 9369            h_flex().h_full().flex_1().gap_2().child(Icon::new(icon))
 9370        }
 9371
 9372        let completion = match &self.active_edit_prediction {
 9373            Some(prediction) => {
 9374                if !self.has_visible_completions_menu() {
 9375                    const RADIUS: Pixels = px(6.);
 9376                    const BORDER_WIDTH: Pixels = px(1.);
 9377
 9378                    return Some(
 9379                        h_flex()
 9380                            .elevation_2(cx)
 9381                            .border(BORDER_WIDTH)
 9382                            .border_color(cx.theme().colors().border)
 9383                            .when(accept_keystroke.is_none(), |el| {
 9384                                el.border_color(cx.theme().status().error)
 9385                            })
 9386                            .rounded(RADIUS)
 9387                            .rounded_tl(px(0.))
 9388                            .overflow_hidden()
 9389                            .child(div().px_1p5().child(match &prediction.completion {
 9390                                EditPrediction::MoveWithin { target, snapshot } => {
 9391                                    use text::ToPoint as _;
 9392                                    if target.text_anchor.to_point(snapshot).row > cursor_point.row
 9393                                    {
 9394                                        Icon::new(IconName::ZedPredictDown)
 9395                                    } else {
 9396                                        Icon::new(IconName::ZedPredictUp)
 9397                                    }
 9398                                }
 9399                                EditPrediction::MoveOutside { .. } => {
 9400                                    // TODO [zeta2] custom icon for external jump?
 9401                                    Icon::new(provider_icon)
 9402                                }
 9403                                EditPrediction::Edit { .. } => Icon::new(provider_icon),
 9404                            }))
 9405                            .child(
 9406                                h_flex()
 9407                                    .gap_1()
 9408                                    .py_1()
 9409                                    .px_2()
 9410                                    .rounded_r(RADIUS - BORDER_WIDTH)
 9411                                    .border_l_1()
 9412                                    .border_color(cx.theme().colors().border)
 9413                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9414                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 9415                                        el.child(
 9416                                            Label::new("Hold")
 9417                                                .size(LabelSize::Small)
 9418                                                .when(accept_keystroke.is_none(), |el| {
 9419                                                    el.strikethrough()
 9420                                                })
 9421                                                .line_height_style(LineHeightStyle::UiLabel),
 9422                                        )
 9423                                    })
 9424                                    .id("edit_prediction_cursor_popover_keybind")
 9425                                    .when(accept_keystroke.is_none(), |el| {
 9426                                        let status_colors = cx.theme().status();
 9427
 9428                                        el.bg(status_colors.error_background)
 9429                                            .border_color(status_colors.error.opacity(0.6))
 9430                                            .child(Icon::new(IconName::Info).color(Color::Error))
 9431                                            .cursor_default()
 9432                                            .hoverable_tooltip(move |_window, cx| {
 9433                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 9434                                                    .into()
 9435                                            })
 9436                                    })
 9437                                    .when_some(
 9438                                        accept_keystroke.as_ref(),
 9439                                        |el, accept_keystroke| {
 9440                                            el.child(h_flex().children(ui::render_modifiers(
 9441                                                accept_keystroke.modifiers(),
 9442                                                PlatformStyle::platform(),
 9443                                                Some(Color::Default),
 9444                                                Some(IconSize::XSmall.rems().into()),
 9445                                                false,
 9446                                            )))
 9447                                        },
 9448                                    ),
 9449                            )
 9450                            .into_any(),
 9451                    );
 9452                }
 9453
 9454                self.render_edit_prediction_cursor_popover_preview(
 9455                    prediction,
 9456                    cursor_point,
 9457                    style,
 9458                    cx,
 9459                )?
 9460            }
 9461
 9462            None if is_refreshing => match &self.stale_edit_prediction_in_menu {
 9463                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 9464                    stale_completion,
 9465                    cursor_point,
 9466                    style,
 9467                    cx,
 9468                )?,
 9469
 9470                None => pending_completion_container(provider_icon)
 9471                    .child(Label::new("...").size(LabelSize::Small)),
 9472            },
 9473
 9474            None => pending_completion_container(provider_icon)
 9475                .child(Label::new("...").size(LabelSize::Small)),
 9476        };
 9477
 9478        let completion = if is_refreshing || self.active_edit_prediction.is_none() {
 9479            completion
 9480                .with_animation(
 9481                    "loading-completion",
 9482                    Animation::new(Duration::from_secs(2))
 9483                        .repeat()
 9484                        .with_easing(pulsating_between(0.4, 0.8)),
 9485                    |label, delta| label.opacity(delta),
 9486                )
 9487                .into_any_element()
 9488        } else {
 9489            completion.into_any_element()
 9490        };
 9491
 9492        let has_completion = self.active_edit_prediction.is_some();
 9493
 9494        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9495        Some(
 9496            h_flex()
 9497                .min_w(min_width)
 9498                .max_w(max_width)
 9499                .flex_1()
 9500                .elevation_2(cx)
 9501                .border_color(cx.theme().colors().border)
 9502                .child(
 9503                    div()
 9504                        .flex_1()
 9505                        .py_1()
 9506                        .px_2()
 9507                        .overflow_hidden()
 9508                        .child(completion),
 9509                )
 9510                .when_some(accept_keystroke, |el, accept_keystroke| {
 9511                    if !accept_keystroke.modifiers().modified() {
 9512                        return el;
 9513                    }
 9514
 9515                    el.child(
 9516                        h_flex()
 9517                            .h_full()
 9518                            .border_l_1()
 9519                            .rounded_r_lg()
 9520                            .border_color(cx.theme().colors().border)
 9521                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9522                            .gap_1()
 9523                            .py_1()
 9524                            .px_2()
 9525                            .child(
 9526                                h_flex()
 9527                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9528                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 9529                                    .child(h_flex().children(ui::render_modifiers(
 9530                                        accept_keystroke.modifiers(),
 9531                                        PlatformStyle::platform(),
 9532                                        Some(if !has_completion {
 9533                                            Color::Muted
 9534                                        } else {
 9535                                            Color::Default
 9536                                        }),
 9537                                        None,
 9538                                        false,
 9539                                    ))),
 9540                            )
 9541                            .child(Label::new("Preview").into_any_element())
 9542                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 9543                    )
 9544                })
 9545                .into_any(),
 9546        )
 9547    }
 9548
 9549    fn render_edit_prediction_cursor_popover_preview(
 9550        &self,
 9551        completion: &EditPredictionState,
 9552        cursor_point: Point,
 9553        style: &EditorStyle,
 9554        cx: &mut Context<Editor>,
 9555    ) -> Option<Div> {
 9556        use text::ToPoint as _;
 9557
 9558        fn render_relative_row_jump(
 9559            prefix: impl Into<String>,
 9560            current_row: u32,
 9561            target_row: u32,
 9562        ) -> Div {
 9563            let (row_diff, arrow) = if target_row < current_row {
 9564                (current_row - target_row, IconName::ArrowUp)
 9565            } else {
 9566                (target_row - current_row, IconName::ArrowDown)
 9567            };
 9568
 9569            h_flex()
 9570                .child(
 9571                    Label::new(format!("{}{}", prefix.into(), row_diff))
 9572                        .color(Color::Muted)
 9573                        .size(LabelSize::Small),
 9574                )
 9575                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 9576        }
 9577
 9578        let supports_jump = self
 9579            .edit_prediction_provider
 9580            .as_ref()
 9581            .map(|provider| provider.provider.supports_jump_to_edit())
 9582            .unwrap_or(true);
 9583
 9584        match &completion.completion {
 9585            EditPrediction::MoveWithin {
 9586                target, snapshot, ..
 9587            } => {
 9588                if !supports_jump {
 9589                    return None;
 9590                }
 9591
 9592                Some(
 9593                    h_flex()
 9594                        .px_2()
 9595                        .gap_2()
 9596                        .flex_1()
 9597                        .child(
 9598                            if target.text_anchor.to_point(snapshot).row > cursor_point.row {
 9599                                Icon::new(IconName::ZedPredictDown)
 9600                            } else {
 9601                                Icon::new(IconName::ZedPredictUp)
 9602                            },
 9603                        )
 9604                        .child(Label::new("Jump to Edit")),
 9605                )
 9606            }
 9607            EditPrediction::MoveOutside { snapshot, .. } => {
 9608                let file_name = snapshot
 9609                    .file()
 9610                    .map(|file| file.file_name(cx))
 9611                    .unwrap_or("untitled");
 9612                Some(
 9613                    h_flex()
 9614                        .px_2()
 9615                        .gap_2()
 9616                        .flex_1()
 9617                        .child(Icon::new(IconName::ZedPredict))
 9618                        .child(Label::new(format!("Jump to {file_name}"))),
 9619                )
 9620            }
 9621            EditPrediction::Edit {
 9622                edits,
 9623                edit_preview,
 9624                snapshot,
 9625                display_mode: _,
 9626            } => {
 9627                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(snapshot).row;
 9628
 9629                let (highlighted_edits, has_more_lines) =
 9630                    if let Some(edit_preview) = edit_preview.as_ref() {
 9631                        crate::edit_prediction_edit_text(snapshot, edits, edit_preview, true, cx)
 9632                            .first_line_preview()
 9633                    } else {
 9634                        crate::edit_prediction_fallback_text(edits, cx).first_line_preview()
 9635                    };
 9636
 9637                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 9638                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 9639
 9640                let preview = h_flex()
 9641                    .gap_1()
 9642                    .min_w_16()
 9643                    .child(styled_text)
 9644                    .when(has_more_lines, |parent| parent.child(""));
 9645
 9646                let left = if supports_jump && first_edit_row != cursor_point.row {
 9647                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 9648                        .into_any_element()
 9649                } else {
 9650                    let icon_name =
 9651                        Editor::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9652                    Icon::new(icon_name).into_any_element()
 9653                };
 9654
 9655                Some(
 9656                    h_flex()
 9657                        .h_full()
 9658                        .flex_1()
 9659                        .gap_2()
 9660                        .pr_1()
 9661                        .overflow_x_hidden()
 9662                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9663                        .child(left)
 9664                        .child(preview),
 9665                )
 9666            }
 9667        }
 9668    }
 9669
 9670    pub fn render_context_menu(
 9671        &self,
 9672        style: &EditorStyle,
 9673        max_height_in_lines: u32,
 9674        window: &mut Window,
 9675        cx: &mut Context<Editor>,
 9676    ) -> Option<AnyElement> {
 9677        let menu = self.context_menu.borrow();
 9678        let menu = menu.as_ref()?;
 9679        if !menu.visible() {
 9680            return None;
 9681        };
 9682        Some(menu.render(style, max_height_in_lines, window, cx))
 9683    }
 9684
 9685    fn render_context_menu_aside(
 9686        &mut self,
 9687        max_size: Size<Pixels>,
 9688        window: &mut Window,
 9689        cx: &mut Context<Editor>,
 9690    ) -> Option<AnyElement> {
 9691        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 9692            if menu.visible() {
 9693                menu.render_aside(max_size, window, cx)
 9694            } else {
 9695                None
 9696            }
 9697        })
 9698    }
 9699
 9700    fn hide_context_menu(
 9701        &mut self,
 9702        window: &mut Window,
 9703        cx: &mut Context<Self>,
 9704    ) -> Option<CodeContextMenu> {
 9705        cx.notify();
 9706        self.completion_tasks.clear();
 9707        let context_menu = self.context_menu.borrow_mut().take();
 9708        self.stale_edit_prediction_in_menu.take();
 9709        self.update_visible_edit_prediction(window, cx);
 9710        if let Some(CodeContextMenu::Completions(_)) = &context_menu
 9711            && let Some(completion_provider) = &self.completion_provider
 9712        {
 9713            completion_provider.selection_changed(None, window, cx);
 9714        }
 9715        context_menu
 9716    }
 9717
 9718    fn show_snippet_choices(
 9719        &mut self,
 9720        choices: &Vec<String>,
 9721        selection: Range<Anchor>,
 9722        cx: &mut Context<Self>,
 9723    ) {
 9724        let Some((_, buffer, _)) = self
 9725            .buffer()
 9726            .read(cx)
 9727            .excerpt_containing(selection.start, cx)
 9728        else {
 9729            return;
 9730        };
 9731        let Some((_, end_buffer, _)) = self.buffer().read(cx).excerpt_containing(selection.end, cx)
 9732        else {
 9733            return;
 9734        };
 9735        if buffer != end_buffer {
 9736            log::error!("expected anchor range to have matching buffer IDs");
 9737            return;
 9738        }
 9739
 9740        let id = post_inc(&mut self.next_completion_id);
 9741        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 9742        *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 9743            CompletionsMenu::new_snippet_choices(
 9744                id,
 9745                true,
 9746                choices,
 9747                selection,
 9748                buffer,
 9749                snippet_sort_order,
 9750            ),
 9751        ));
 9752    }
 9753
 9754    pub fn insert_snippet(
 9755        &mut self,
 9756        insertion_ranges: &[Range<usize>],
 9757        snippet: Snippet,
 9758        window: &mut Window,
 9759        cx: &mut Context<Self>,
 9760    ) -> Result<()> {
 9761        struct Tabstop<T> {
 9762            is_end_tabstop: bool,
 9763            ranges: Vec<Range<T>>,
 9764            choices: Option<Vec<String>>,
 9765        }
 9766
 9767        let tabstops = self.buffer.update(cx, |buffer, cx| {
 9768            let snippet_text: Arc<str> = snippet.text.clone().into();
 9769            let edits = insertion_ranges
 9770                .iter()
 9771                .cloned()
 9772                .map(|range| (range, snippet_text.clone()));
 9773            let autoindent_mode = AutoindentMode::Block {
 9774                original_indent_columns: Vec::new(),
 9775            };
 9776            buffer.edit(edits, Some(autoindent_mode), cx);
 9777
 9778            let snapshot = &*buffer.read(cx);
 9779            let snippet = &snippet;
 9780            snippet
 9781                .tabstops
 9782                .iter()
 9783                .map(|tabstop| {
 9784                    let is_end_tabstop = tabstop.ranges.first().is_some_and(|tabstop| {
 9785                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 9786                    });
 9787                    let mut tabstop_ranges = tabstop
 9788                        .ranges
 9789                        .iter()
 9790                        .flat_map(|tabstop_range| {
 9791                            let mut delta = 0_isize;
 9792                            insertion_ranges.iter().map(move |insertion_range| {
 9793                                let insertion_start = insertion_range.start as isize + delta;
 9794                                delta +=
 9795                                    snippet.text.len() as isize - insertion_range.len() as isize;
 9796
 9797                                let start = ((insertion_start + tabstop_range.start) as usize)
 9798                                    .min(snapshot.len());
 9799                                let end = ((insertion_start + tabstop_range.end) as usize)
 9800                                    .min(snapshot.len());
 9801                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 9802                            })
 9803                        })
 9804                        .collect::<Vec<_>>();
 9805                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 9806
 9807                    Tabstop {
 9808                        is_end_tabstop,
 9809                        ranges: tabstop_ranges,
 9810                        choices: tabstop.choices.clone(),
 9811                    }
 9812                })
 9813                .collect::<Vec<_>>()
 9814        });
 9815        if let Some(tabstop) = tabstops.first() {
 9816            self.change_selections(Default::default(), window, cx, |s| {
 9817                // Reverse order so that the first range is the newest created selection.
 9818                // Completions will use it and autoscroll will prioritize it.
 9819                s.select_ranges(tabstop.ranges.iter().rev().cloned());
 9820            });
 9821
 9822            if let Some(choices) = &tabstop.choices
 9823                && let Some(selection) = tabstop.ranges.first()
 9824            {
 9825                self.show_snippet_choices(choices, selection.clone(), cx)
 9826            }
 9827
 9828            // If we're already at the last tabstop and it's at the end of the snippet,
 9829            // we're done, we don't need to keep the state around.
 9830            if !tabstop.is_end_tabstop {
 9831                let choices = tabstops
 9832                    .iter()
 9833                    .map(|tabstop| tabstop.choices.clone())
 9834                    .collect();
 9835
 9836                let ranges = tabstops
 9837                    .into_iter()
 9838                    .map(|tabstop| tabstop.ranges)
 9839                    .collect::<Vec<_>>();
 9840
 9841                self.snippet_stack.push(SnippetState {
 9842                    active_index: 0,
 9843                    ranges,
 9844                    choices,
 9845                });
 9846            }
 9847
 9848            // Check whether the just-entered snippet ends with an auto-closable bracket.
 9849            if self.autoclose_regions.is_empty() {
 9850                let snapshot = self.buffer.read(cx).snapshot(cx);
 9851                for selection in &mut self.selections.all::<Point>(&self.display_snapshot(cx)) {
 9852                    let selection_head = selection.head();
 9853                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 9854                        continue;
 9855                    };
 9856
 9857                    let mut bracket_pair = None;
 9858                    let max_lookup_length = scope
 9859                        .brackets()
 9860                        .map(|(pair, _)| {
 9861                            pair.start
 9862                                .as_str()
 9863                                .chars()
 9864                                .count()
 9865                                .max(pair.end.as_str().chars().count())
 9866                        })
 9867                        .max();
 9868                    if let Some(max_lookup_length) = max_lookup_length {
 9869                        let next_text = snapshot
 9870                            .chars_at(selection_head)
 9871                            .take(max_lookup_length)
 9872                            .collect::<String>();
 9873                        let prev_text = snapshot
 9874                            .reversed_chars_at(selection_head)
 9875                            .take(max_lookup_length)
 9876                            .collect::<String>();
 9877
 9878                        for (pair, enabled) in scope.brackets() {
 9879                            if enabled
 9880                                && pair.close
 9881                                && prev_text.starts_with(pair.start.as_str())
 9882                                && next_text.starts_with(pair.end.as_str())
 9883                            {
 9884                                bracket_pair = Some(pair.clone());
 9885                                break;
 9886                            }
 9887                        }
 9888                    }
 9889
 9890                    if let Some(pair) = bracket_pair {
 9891                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 9892                        let autoclose_enabled =
 9893                            self.use_autoclose && snapshot_settings.use_autoclose;
 9894                        if autoclose_enabled {
 9895                            let start = snapshot.anchor_after(selection_head);
 9896                            let end = snapshot.anchor_after(selection_head);
 9897                            self.autoclose_regions.push(AutocloseRegion {
 9898                                selection_id: selection.id,
 9899                                range: start..end,
 9900                                pair,
 9901                            });
 9902                        }
 9903                    }
 9904                }
 9905            }
 9906        }
 9907        Ok(())
 9908    }
 9909
 9910    pub fn move_to_next_snippet_tabstop(
 9911        &mut self,
 9912        window: &mut Window,
 9913        cx: &mut Context<Self>,
 9914    ) -> bool {
 9915        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 9916    }
 9917
 9918    pub fn move_to_prev_snippet_tabstop(
 9919        &mut self,
 9920        window: &mut Window,
 9921        cx: &mut Context<Self>,
 9922    ) -> bool {
 9923        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 9924    }
 9925
 9926    pub fn move_to_snippet_tabstop(
 9927        &mut self,
 9928        bias: Bias,
 9929        window: &mut Window,
 9930        cx: &mut Context<Self>,
 9931    ) -> bool {
 9932        if let Some(mut snippet) = self.snippet_stack.pop() {
 9933            match bias {
 9934                Bias::Left => {
 9935                    if snippet.active_index > 0 {
 9936                        snippet.active_index -= 1;
 9937                    } else {
 9938                        self.snippet_stack.push(snippet);
 9939                        return false;
 9940                    }
 9941                }
 9942                Bias::Right => {
 9943                    if snippet.active_index + 1 < snippet.ranges.len() {
 9944                        snippet.active_index += 1;
 9945                    } else {
 9946                        self.snippet_stack.push(snippet);
 9947                        return false;
 9948                    }
 9949                }
 9950            }
 9951            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 9952                self.change_selections(Default::default(), window, cx, |s| {
 9953                    // Reverse order so that the first range is the newest created selection.
 9954                    // Completions will use it and autoscroll will prioritize it.
 9955                    s.select_ranges(current_ranges.iter().rev().cloned())
 9956                });
 9957
 9958                if let Some(choices) = &snippet.choices[snippet.active_index]
 9959                    && let Some(selection) = current_ranges.first()
 9960                {
 9961                    self.show_snippet_choices(choices, selection.clone(), cx);
 9962                }
 9963
 9964                // If snippet state is not at the last tabstop, push it back on the stack
 9965                if snippet.active_index + 1 < snippet.ranges.len() {
 9966                    self.snippet_stack.push(snippet);
 9967                }
 9968                return true;
 9969            }
 9970        }
 9971
 9972        false
 9973    }
 9974
 9975    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 9976        self.transact(window, cx, |this, window, cx| {
 9977            this.select_all(&SelectAll, window, cx);
 9978            this.insert("", window, cx);
 9979        });
 9980    }
 9981
 9982    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
 9983        if self.read_only(cx) {
 9984            return;
 9985        }
 9986        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9987        self.transact(window, cx, |this, window, cx| {
 9988            this.select_autoclose_pair(window, cx);
 9989
 9990            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 9991
 9992            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
 9993            if !this.linked_edit_ranges.is_empty() {
 9994                let selections = this.selections.all::<MultiBufferPoint>(&display_map);
 9995                let snapshot = this.buffer.read(cx).snapshot(cx);
 9996
 9997                for selection in selections.iter() {
 9998                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
 9999                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
10000                    if selection_start.buffer_id != selection_end.buffer_id {
10001                        continue;
10002                    }
10003                    if let Some(ranges) =
10004                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
10005                    {
10006                        for (buffer, entries) in ranges {
10007                            linked_ranges.entry(buffer).or_default().extend(entries);
10008                        }
10009                    }
10010                }
10011            }
10012
10013            let mut selections = this.selections.all::<MultiBufferPoint>(&display_map);
10014            for selection in &mut selections {
10015                if selection.is_empty() {
10016                    let old_head = selection.head();
10017                    let mut new_head =
10018                        movement::left(&display_map, old_head.to_display_point(&display_map))
10019                            .to_point(&display_map);
10020                    if let Some((buffer, line_buffer_range)) = display_map
10021                        .buffer_snapshot()
10022                        .buffer_line_for_row(MultiBufferRow(old_head.row))
10023                    {
10024                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
10025                        let indent_len = match indent_size.kind {
10026                            IndentKind::Space => {
10027                                buffer.settings_at(line_buffer_range.start, cx).tab_size
10028                            }
10029                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
10030                        };
10031                        if old_head.column <= indent_size.len && old_head.column > 0 {
10032                            let indent_len = indent_len.get();
10033                            new_head = cmp::min(
10034                                new_head,
10035                                MultiBufferPoint::new(
10036                                    old_head.row,
10037                                    ((old_head.column - 1) / indent_len) * indent_len,
10038                                ),
10039                            );
10040                        }
10041                    }
10042
10043                    selection.set_head(new_head, SelectionGoal::None);
10044                }
10045            }
10046
10047            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10048            this.insert("", window, cx);
10049            let empty_str: Arc<str> = Arc::from("");
10050            for (buffer, edits) in linked_ranges {
10051                let snapshot = buffer.read(cx).snapshot();
10052                use text::ToPoint as TP;
10053
10054                let edits = edits
10055                    .into_iter()
10056                    .map(|range| {
10057                        let end_point = TP::to_point(&range.end, &snapshot);
10058                        let mut start_point = TP::to_point(&range.start, &snapshot);
10059
10060                        if end_point == start_point {
10061                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
10062                                .saturating_sub(1);
10063                            start_point =
10064                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
10065                        };
10066
10067                        (start_point..end_point, empty_str.clone())
10068                    })
10069                    .sorted_by_key(|(range, _)| range.start)
10070                    .collect::<Vec<_>>();
10071                buffer.update(cx, |this, cx| {
10072                    this.edit(edits, None, cx);
10073                })
10074            }
10075            this.refresh_edit_prediction(true, false, window, cx);
10076            refresh_linked_ranges(this, window, cx);
10077        });
10078    }
10079
10080    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
10081        if self.read_only(cx) {
10082            return;
10083        }
10084        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10085        self.transact(window, cx, |this, window, cx| {
10086            this.change_selections(Default::default(), window, cx, |s| {
10087                s.move_with(|map, selection| {
10088                    if selection.is_empty() {
10089                        let cursor = movement::right(map, selection.head());
10090                        selection.end = cursor;
10091                        selection.reversed = true;
10092                        selection.goal = SelectionGoal::None;
10093                    }
10094                })
10095            });
10096            this.insert("", window, cx);
10097            this.refresh_edit_prediction(true, false, window, cx);
10098        });
10099    }
10100
10101    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
10102        if self.mode.is_single_line() {
10103            cx.propagate();
10104            return;
10105        }
10106
10107        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10108        if self.move_to_prev_snippet_tabstop(window, cx) {
10109            return;
10110        }
10111        self.outdent(&Outdent, window, cx);
10112    }
10113
10114    pub fn next_snippet_tabstop(
10115        &mut self,
10116        _: &NextSnippetTabstop,
10117        window: &mut Window,
10118        cx: &mut Context<Self>,
10119    ) {
10120        if self.mode.is_single_line() || self.snippet_stack.is_empty() {
10121            cx.propagate();
10122            return;
10123        }
10124
10125        if self.move_to_next_snippet_tabstop(window, cx) {
10126            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10127            return;
10128        }
10129        cx.propagate();
10130    }
10131
10132    pub fn previous_snippet_tabstop(
10133        &mut self,
10134        _: &PreviousSnippetTabstop,
10135        window: &mut Window,
10136        cx: &mut Context<Self>,
10137    ) {
10138        if self.mode.is_single_line() || self.snippet_stack.is_empty() {
10139            cx.propagate();
10140            return;
10141        }
10142
10143        if self.move_to_prev_snippet_tabstop(window, cx) {
10144            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10145            return;
10146        }
10147        cx.propagate();
10148    }
10149
10150    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
10151        if self.mode.is_single_line() {
10152            cx.propagate();
10153            return;
10154        }
10155
10156        if self.move_to_next_snippet_tabstop(window, cx) {
10157            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10158            return;
10159        }
10160        if self.read_only(cx) {
10161            return;
10162        }
10163        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10164        let mut selections = self.selections.all_adjusted(&self.display_snapshot(cx));
10165        let buffer = self.buffer.read(cx);
10166        let snapshot = buffer.snapshot(cx);
10167        let rows_iter = selections.iter().map(|s| s.head().row);
10168        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
10169
10170        let has_some_cursor_in_whitespace = selections
10171            .iter()
10172            .filter(|selection| selection.is_empty())
10173            .any(|selection| {
10174                let cursor = selection.head();
10175                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10176                cursor.column < current_indent.len
10177            });
10178
10179        let mut edits = Vec::new();
10180        let mut prev_edited_row = 0;
10181        let mut row_delta = 0;
10182        for selection in &mut selections {
10183            if selection.start.row != prev_edited_row {
10184                row_delta = 0;
10185            }
10186            prev_edited_row = selection.end.row;
10187
10188            // If the selection is non-empty, then increase the indentation of the selected lines.
10189            if !selection.is_empty() {
10190                row_delta =
10191                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10192                continue;
10193            }
10194
10195            let cursor = selection.head();
10196            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10197            if let Some(suggested_indent) =
10198                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
10199            {
10200                // Don't do anything if already at suggested indent
10201                // and there is any other cursor which is not
10202                if has_some_cursor_in_whitespace
10203                    && cursor.column == current_indent.len
10204                    && current_indent.len == suggested_indent.len
10205                {
10206                    continue;
10207                }
10208
10209                // Adjust line and move cursor to suggested indent
10210                // if cursor is not at suggested indent
10211                if cursor.column < suggested_indent.len
10212                    && cursor.column <= current_indent.len
10213                    && current_indent.len <= suggested_indent.len
10214                {
10215                    selection.start = Point::new(cursor.row, suggested_indent.len);
10216                    selection.end = selection.start;
10217                    if row_delta == 0 {
10218                        edits.extend(Buffer::edit_for_indent_size_adjustment(
10219                            cursor.row,
10220                            current_indent,
10221                            suggested_indent,
10222                        ));
10223                        row_delta = suggested_indent.len - current_indent.len;
10224                    }
10225                    continue;
10226                }
10227
10228                // If current indent is more than suggested indent
10229                // only move cursor to current indent and skip indent
10230                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
10231                    selection.start = Point::new(cursor.row, current_indent.len);
10232                    selection.end = selection.start;
10233                    continue;
10234                }
10235            }
10236
10237            // Otherwise, insert a hard or soft tab.
10238            let settings = buffer.language_settings_at(cursor, cx);
10239            let tab_size = if settings.hard_tabs {
10240                IndentSize::tab()
10241            } else {
10242                let tab_size = settings.tab_size.get();
10243                let indent_remainder = snapshot
10244                    .text_for_range(Point::new(cursor.row, 0)..cursor)
10245                    .flat_map(str::chars)
10246                    .fold(row_delta % tab_size, |counter: u32, c| {
10247                        if c == '\t' {
10248                            0
10249                        } else {
10250                            (counter + 1) % tab_size
10251                        }
10252                    });
10253
10254                let chars_to_next_tab_stop = tab_size - indent_remainder;
10255                IndentSize::spaces(chars_to_next_tab_stop)
10256            };
10257            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
10258            selection.end = selection.start;
10259            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
10260            row_delta += tab_size.len;
10261        }
10262
10263        self.transact(window, cx, |this, window, cx| {
10264            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10265            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10266            this.refresh_edit_prediction(true, false, window, cx);
10267        });
10268    }
10269
10270    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
10271        if self.read_only(cx) {
10272            return;
10273        }
10274        if self.mode.is_single_line() {
10275            cx.propagate();
10276            return;
10277        }
10278
10279        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10280        let mut selections = self.selections.all::<Point>(&self.display_snapshot(cx));
10281        let mut prev_edited_row = 0;
10282        let mut row_delta = 0;
10283        let mut edits = Vec::new();
10284        let buffer = self.buffer.read(cx);
10285        let snapshot = buffer.snapshot(cx);
10286        for selection in &mut selections {
10287            if selection.start.row != prev_edited_row {
10288                row_delta = 0;
10289            }
10290            prev_edited_row = selection.end.row;
10291
10292            row_delta =
10293                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10294        }
10295
10296        self.transact(window, cx, |this, window, cx| {
10297            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10298            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10299        });
10300    }
10301
10302    fn indent_selection(
10303        buffer: &MultiBuffer,
10304        snapshot: &MultiBufferSnapshot,
10305        selection: &mut Selection<Point>,
10306        edits: &mut Vec<(Range<Point>, String)>,
10307        delta_for_start_row: u32,
10308        cx: &App,
10309    ) -> u32 {
10310        let settings = buffer.language_settings_at(selection.start, cx);
10311        let tab_size = settings.tab_size.get();
10312        let indent_kind = if settings.hard_tabs {
10313            IndentKind::Tab
10314        } else {
10315            IndentKind::Space
10316        };
10317        let mut start_row = selection.start.row;
10318        let mut end_row = selection.end.row + 1;
10319
10320        // If a selection ends at the beginning of a line, don't indent
10321        // that last line.
10322        if selection.end.column == 0 && selection.end.row > selection.start.row {
10323            end_row -= 1;
10324        }
10325
10326        // Avoid re-indenting a row that has already been indented by a
10327        // previous selection, but still update this selection's column
10328        // to reflect that indentation.
10329        if delta_for_start_row > 0 {
10330            start_row += 1;
10331            selection.start.column += delta_for_start_row;
10332            if selection.end.row == selection.start.row {
10333                selection.end.column += delta_for_start_row;
10334            }
10335        }
10336
10337        let mut delta_for_end_row = 0;
10338        let has_multiple_rows = start_row + 1 != end_row;
10339        for row in start_row..end_row {
10340            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
10341            let indent_delta = match (current_indent.kind, indent_kind) {
10342                (IndentKind::Space, IndentKind::Space) => {
10343                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
10344                    IndentSize::spaces(columns_to_next_tab_stop)
10345                }
10346                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
10347                (_, IndentKind::Tab) => IndentSize::tab(),
10348            };
10349
10350            let start = if has_multiple_rows || current_indent.len < selection.start.column {
10351                0
10352            } else {
10353                selection.start.column
10354            };
10355            let row_start = Point::new(row, start);
10356            edits.push((
10357                row_start..row_start,
10358                indent_delta.chars().collect::<String>(),
10359            ));
10360
10361            // Update this selection's endpoints to reflect the indentation.
10362            if row == selection.start.row {
10363                selection.start.column += indent_delta.len;
10364            }
10365            if row == selection.end.row {
10366                selection.end.column += indent_delta.len;
10367                delta_for_end_row = indent_delta.len;
10368            }
10369        }
10370
10371        if selection.start.row == selection.end.row {
10372            delta_for_start_row + delta_for_end_row
10373        } else {
10374            delta_for_end_row
10375        }
10376    }
10377
10378    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
10379        if self.read_only(cx) {
10380            return;
10381        }
10382        if self.mode.is_single_line() {
10383            cx.propagate();
10384            return;
10385        }
10386
10387        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10388        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10389        let selections = self.selections.all::<Point>(&display_map);
10390        let mut deletion_ranges = Vec::new();
10391        let mut last_outdent = None;
10392        {
10393            let buffer = self.buffer.read(cx);
10394            let snapshot = buffer.snapshot(cx);
10395            for selection in &selections {
10396                let settings = buffer.language_settings_at(selection.start, cx);
10397                let tab_size = settings.tab_size.get();
10398                let mut rows = selection.spanned_rows(false, &display_map);
10399
10400                // Avoid re-outdenting a row that has already been outdented by a
10401                // previous selection.
10402                if let Some(last_row) = last_outdent
10403                    && last_row == rows.start
10404                {
10405                    rows.start = rows.start.next_row();
10406                }
10407                let has_multiple_rows = rows.len() > 1;
10408                for row in rows.iter_rows() {
10409                    let indent_size = snapshot.indent_size_for_line(row);
10410                    if indent_size.len > 0 {
10411                        let deletion_len = match indent_size.kind {
10412                            IndentKind::Space => {
10413                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
10414                                if columns_to_prev_tab_stop == 0 {
10415                                    tab_size
10416                                } else {
10417                                    columns_to_prev_tab_stop
10418                                }
10419                            }
10420                            IndentKind::Tab => 1,
10421                        };
10422                        let start = if has_multiple_rows
10423                            || deletion_len > selection.start.column
10424                            || indent_size.len < selection.start.column
10425                        {
10426                            0
10427                        } else {
10428                            selection.start.column - deletion_len
10429                        };
10430                        deletion_ranges.push(
10431                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
10432                        );
10433                        last_outdent = Some(row);
10434                    }
10435                }
10436            }
10437        }
10438
10439        self.transact(window, cx, |this, window, cx| {
10440            this.buffer.update(cx, |buffer, cx| {
10441                let empty_str: Arc<str> = Arc::default();
10442                buffer.edit(
10443                    deletion_ranges
10444                        .into_iter()
10445                        .map(|range| (range, empty_str.clone())),
10446                    None,
10447                    cx,
10448                );
10449            });
10450            let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
10451            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10452        });
10453    }
10454
10455    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
10456        if self.read_only(cx) {
10457            return;
10458        }
10459        if self.mode.is_single_line() {
10460            cx.propagate();
10461            return;
10462        }
10463
10464        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10465        let selections = self
10466            .selections
10467            .all::<usize>(&self.display_snapshot(cx))
10468            .into_iter()
10469            .map(|s| s.range());
10470
10471        self.transact(window, cx, |this, window, cx| {
10472            this.buffer.update(cx, |buffer, cx| {
10473                buffer.autoindent_ranges(selections, cx);
10474            });
10475            let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
10476            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10477        });
10478    }
10479
10480    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
10481        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10482        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10483        let selections = self.selections.all::<Point>(&display_map);
10484
10485        let mut new_cursors = Vec::new();
10486        let mut edit_ranges = Vec::new();
10487        let mut selections = selections.iter().peekable();
10488        while let Some(selection) = selections.next() {
10489            let mut rows = selection.spanned_rows(false, &display_map);
10490
10491            // Accumulate contiguous regions of rows that we want to delete.
10492            while let Some(next_selection) = selections.peek() {
10493                let next_rows = next_selection.spanned_rows(false, &display_map);
10494                if next_rows.start <= rows.end {
10495                    rows.end = next_rows.end;
10496                    selections.next().unwrap();
10497                } else {
10498                    break;
10499                }
10500            }
10501
10502            let buffer = display_map.buffer_snapshot();
10503            let mut edit_start = ToOffset::to_offset(&Point::new(rows.start.0, 0), buffer);
10504            let (edit_end, target_row) = if buffer.max_point().row >= rows.end.0 {
10505                // If there's a line after the range, delete the \n from the end of the row range
10506                (
10507                    ToOffset::to_offset(&Point::new(rows.end.0, 0), buffer),
10508                    rows.end,
10509                )
10510            } else {
10511                // If there isn't a line after the range, delete the \n from the line before the
10512                // start of the row range
10513                edit_start = edit_start.saturating_sub(1);
10514                (buffer.len(), rows.start.previous_row())
10515            };
10516
10517            let text_layout_details = self.text_layout_details(window);
10518            let x = display_map.x_for_display_point(
10519                selection.head().to_display_point(&display_map),
10520                &text_layout_details,
10521            );
10522            let row = Point::new(target_row.0, 0)
10523                .to_display_point(&display_map)
10524                .row();
10525            let column = display_map.display_column_for_x(row, x, &text_layout_details);
10526
10527            new_cursors.push((
10528                selection.id,
10529                buffer.anchor_after(DisplayPoint::new(row, column).to_point(&display_map)),
10530                SelectionGoal::None,
10531            ));
10532            edit_ranges.push(edit_start..edit_end);
10533        }
10534
10535        self.transact(window, cx, |this, window, cx| {
10536            let buffer = this.buffer.update(cx, |buffer, cx| {
10537                let empty_str: Arc<str> = Arc::default();
10538                buffer.edit(
10539                    edit_ranges
10540                        .into_iter()
10541                        .map(|range| (range, empty_str.clone())),
10542                    None,
10543                    cx,
10544                );
10545                buffer.snapshot(cx)
10546            });
10547            let new_selections = new_cursors
10548                .into_iter()
10549                .map(|(id, cursor, goal)| {
10550                    let cursor = cursor.to_point(&buffer);
10551                    Selection {
10552                        id,
10553                        start: cursor,
10554                        end: cursor,
10555                        reversed: false,
10556                        goal,
10557                    }
10558                })
10559                .collect();
10560
10561            this.change_selections(Default::default(), window, cx, |s| {
10562                s.select(new_selections);
10563            });
10564        });
10565    }
10566
10567    pub fn join_lines_impl(
10568        &mut self,
10569        insert_whitespace: bool,
10570        window: &mut Window,
10571        cx: &mut Context<Self>,
10572    ) {
10573        if self.read_only(cx) {
10574            return;
10575        }
10576        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
10577        for selection in self.selections.all::<Point>(&self.display_snapshot(cx)) {
10578            let start = MultiBufferRow(selection.start.row);
10579            // Treat single line selections as if they include the next line. Otherwise this action
10580            // would do nothing for single line selections individual cursors.
10581            let end = if selection.start.row == selection.end.row {
10582                MultiBufferRow(selection.start.row + 1)
10583            } else {
10584                MultiBufferRow(selection.end.row)
10585            };
10586
10587            if let Some(last_row_range) = row_ranges.last_mut()
10588                && start <= last_row_range.end
10589            {
10590                last_row_range.end = end;
10591                continue;
10592            }
10593            row_ranges.push(start..end);
10594        }
10595
10596        let snapshot = self.buffer.read(cx).snapshot(cx);
10597        let mut cursor_positions = Vec::new();
10598        for row_range in &row_ranges {
10599            let anchor = snapshot.anchor_before(Point::new(
10600                row_range.end.previous_row().0,
10601                snapshot.line_len(row_range.end.previous_row()),
10602            ));
10603            cursor_positions.push(anchor..anchor);
10604        }
10605
10606        self.transact(window, cx, |this, window, cx| {
10607            for row_range in row_ranges.into_iter().rev() {
10608                for row in row_range.iter_rows().rev() {
10609                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
10610                    let next_line_row = row.next_row();
10611                    let indent = snapshot.indent_size_for_line(next_line_row);
10612                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
10613
10614                    let replace =
10615                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
10616                            " "
10617                        } else {
10618                            ""
10619                        };
10620
10621                    this.buffer.update(cx, |buffer, cx| {
10622                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
10623                    });
10624                }
10625            }
10626
10627            this.change_selections(Default::default(), window, cx, |s| {
10628                s.select_anchor_ranges(cursor_positions)
10629            });
10630        });
10631    }
10632
10633    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
10634        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10635        self.join_lines_impl(true, window, cx);
10636    }
10637
10638    pub fn sort_lines_case_sensitive(
10639        &mut self,
10640        _: &SortLinesCaseSensitive,
10641        window: &mut Window,
10642        cx: &mut Context<Self>,
10643    ) {
10644        self.manipulate_immutable_lines(window, cx, |lines| lines.sort())
10645    }
10646
10647    pub fn sort_lines_by_length(
10648        &mut self,
10649        _: &SortLinesByLength,
10650        window: &mut Window,
10651        cx: &mut Context<Self>,
10652    ) {
10653        self.manipulate_immutable_lines(window, cx, |lines| {
10654            lines.sort_by_key(|&line| line.chars().count())
10655        })
10656    }
10657
10658    pub fn sort_lines_case_insensitive(
10659        &mut self,
10660        _: &SortLinesCaseInsensitive,
10661        window: &mut Window,
10662        cx: &mut Context<Self>,
10663    ) {
10664        self.manipulate_immutable_lines(window, cx, |lines| {
10665            lines.sort_by_key(|line| line.to_lowercase())
10666        })
10667    }
10668
10669    pub fn unique_lines_case_insensitive(
10670        &mut self,
10671        _: &UniqueLinesCaseInsensitive,
10672        window: &mut Window,
10673        cx: &mut Context<Self>,
10674    ) {
10675        self.manipulate_immutable_lines(window, cx, |lines| {
10676            let mut seen = HashSet::default();
10677            lines.retain(|line| seen.insert(line.to_lowercase()));
10678        })
10679    }
10680
10681    pub fn unique_lines_case_sensitive(
10682        &mut self,
10683        _: &UniqueLinesCaseSensitive,
10684        window: &mut Window,
10685        cx: &mut Context<Self>,
10686    ) {
10687        self.manipulate_immutable_lines(window, cx, |lines| {
10688            let mut seen = HashSet::default();
10689            lines.retain(|line| seen.insert(*line));
10690        })
10691    }
10692
10693    fn enable_wrap_selections_in_tag(&self, cx: &App) -> bool {
10694        let snapshot = self.buffer.read(cx).snapshot(cx);
10695        for selection in self.selections.disjoint_anchors_arc().iter() {
10696            if snapshot
10697                .language_at(selection.start)
10698                .and_then(|lang| lang.config().wrap_characters.as_ref())
10699                .is_some()
10700            {
10701                return true;
10702            }
10703        }
10704        false
10705    }
10706
10707    fn wrap_selections_in_tag(
10708        &mut self,
10709        _: &WrapSelectionsInTag,
10710        window: &mut Window,
10711        cx: &mut Context<Self>,
10712    ) {
10713        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10714
10715        let snapshot = self.buffer.read(cx).snapshot(cx);
10716
10717        let mut edits = Vec::new();
10718        let mut boundaries = Vec::new();
10719
10720        for selection in self
10721            .selections
10722            .all_adjusted(&self.display_snapshot(cx))
10723            .iter()
10724        {
10725            let Some(wrap_config) = snapshot
10726                .language_at(selection.start)
10727                .and_then(|lang| lang.config().wrap_characters.clone())
10728            else {
10729                continue;
10730            };
10731
10732            let open_tag = format!("{}{}", wrap_config.start_prefix, wrap_config.start_suffix);
10733            let close_tag = format!("{}{}", wrap_config.end_prefix, wrap_config.end_suffix);
10734
10735            let start_before = snapshot.anchor_before(selection.start);
10736            let end_after = snapshot.anchor_after(selection.end);
10737
10738            edits.push((start_before..start_before, open_tag));
10739            edits.push((end_after..end_after, close_tag));
10740
10741            boundaries.push((
10742                start_before,
10743                end_after,
10744                wrap_config.start_prefix.len(),
10745                wrap_config.end_suffix.len(),
10746            ));
10747        }
10748
10749        if edits.is_empty() {
10750            return;
10751        }
10752
10753        self.transact(window, cx, |this, window, cx| {
10754            let buffer = this.buffer.update(cx, |buffer, cx| {
10755                buffer.edit(edits, None, cx);
10756                buffer.snapshot(cx)
10757            });
10758
10759            let mut new_selections = Vec::with_capacity(boundaries.len() * 2);
10760            for (start_before, end_after, start_prefix_len, end_suffix_len) in
10761                boundaries.into_iter()
10762            {
10763                let open_offset = start_before.to_offset(&buffer) + start_prefix_len;
10764                let close_offset = end_after.to_offset(&buffer).saturating_sub(end_suffix_len);
10765                new_selections.push(open_offset..open_offset);
10766                new_selections.push(close_offset..close_offset);
10767            }
10768
10769            this.change_selections(Default::default(), window, cx, |s| {
10770                s.select_ranges(new_selections);
10771            });
10772
10773            this.request_autoscroll(Autoscroll::fit(), cx);
10774        });
10775    }
10776
10777    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
10778        let Some(project) = self.project.clone() else {
10779            return;
10780        };
10781        self.reload(project, window, cx)
10782            .detach_and_notify_err(window, cx);
10783    }
10784
10785    pub fn restore_file(
10786        &mut self,
10787        _: &::git::RestoreFile,
10788        window: &mut Window,
10789        cx: &mut Context<Self>,
10790    ) {
10791        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10792        let mut buffer_ids = HashSet::default();
10793        let snapshot = self.buffer().read(cx).snapshot(cx);
10794        for selection in self.selections.all::<usize>(&self.display_snapshot(cx)) {
10795            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
10796        }
10797
10798        let buffer = self.buffer().read(cx);
10799        let ranges = buffer_ids
10800            .into_iter()
10801            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
10802            .collect::<Vec<_>>();
10803
10804        self.restore_hunks_in_ranges(ranges, window, cx);
10805    }
10806
10807    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
10808        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10809        let selections = self
10810            .selections
10811            .all(&self.display_snapshot(cx))
10812            .into_iter()
10813            .map(|s| s.range())
10814            .collect();
10815        self.restore_hunks_in_ranges(selections, window, cx);
10816    }
10817
10818    pub fn restore_hunks_in_ranges(
10819        &mut self,
10820        ranges: Vec<Range<Point>>,
10821        window: &mut Window,
10822        cx: &mut Context<Editor>,
10823    ) {
10824        let mut revert_changes = HashMap::default();
10825        let chunk_by = self
10826            .snapshot(window, cx)
10827            .hunks_for_ranges(ranges)
10828            .into_iter()
10829            .chunk_by(|hunk| hunk.buffer_id);
10830        for (buffer_id, hunks) in &chunk_by {
10831            let hunks = hunks.collect::<Vec<_>>();
10832            for hunk in &hunks {
10833                self.prepare_restore_change(&mut revert_changes, hunk, cx);
10834            }
10835            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
10836        }
10837        drop(chunk_by);
10838        if !revert_changes.is_empty() {
10839            self.transact(window, cx, |editor, window, cx| {
10840                editor.restore(revert_changes, window, cx);
10841            });
10842        }
10843    }
10844
10845    pub fn status_for_buffer_id(&self, buffer_id: BufferId, cx: &App) -> Option<FileStatus> {
10846        if let Some(status) = self
10847            .addons
10848            .iter()
10849            .find_map(|(_, addon)| addon.override_status_for_buffer_id(buffer_id, cx))
10850        {
10851            return Some(status);
10852        }
10853        self.project
10854            .as_ref()?
10855            .read(cx)
10856            .status_for_buffer_id(buffer_id, cx)
10857    }
10858
10859    pub fn open_active_item_in_terminal(
10860        &mut self,
10861        _: &OpenInTerminal,
10862        window: &mut Window,
10863        cx: &mut Context<Self>,
10864    ) {
10865        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
10866            let project_path = buffer.read(cx).project_path(cx)?;
10867            let project = self.project()?.read(cx);
10868            let entry = project.entry_for_path(&project_path, cx)?;
10869            let parent = match &entry.canonical_path {
10870                Some(canonical_path) => canonical_path.to_path_buf(),
10871                None => project.absolute_path(&project_path, cx)?,
10872            }
10873            .parent()?
10874            .to_path_buf();
10875            Some(parent)
10876        }) {
10877            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
10878        }
10879    }
10880
10881    fn set_breakpoint_context_menu(
10882        &mut self,
10883        display_row: DisplayRow,
10884        position: Option<Anchor>,
10885        clicked_point: gpui::Point<Pixels>,
10886        window: &mut Window,
10887        cx: &mut Context<Self>,
10888    ) {
10889        let source = self
10890            .buffer
10891            .read(cx)
10892            .snapshot(cx)
10893            .anchor_before(Point::new(display_row.0, 0u32));
10894
10895        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
10896
10897        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
10898            self,
10899            source,
10900            clicked_point,
10901            context_menu,
10902            window,
10903            cx,
10904        );
10905    }
10906
10907    fn add_edit_breakpoint_block(
10908        &mut self,
10909        anchor: Anchor,
10910        breakpoint: &Breakpoint,
10911        edit_action: BreakpointPromptEditAction,
10912        window: &mut Window,
10913        cx: &mut Context<Self>,
10914    ) {
10915        let weak_editor = cx.weak_entity();
10916        let bp_prompt = cx.new(|cx| {
10917            BreakpointPromptEditor::new(
10918                weak_editor,
10919                anchor,
10920                breakpoint.clone(),
10921                edit_action,
10922                window,
10923                cx,
10924            )
10925        });
10926
10927        let height = bp_prompt.update(cx, |this, cx| {
10928            this.prompt
10929                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
10930        });
10931        let cloned_prompt = bp_prompt.clone();
10932        let blocks = vec![BlockProperties {
10933            style: BlockStyle::Sticky,
10934            placement: BlockPlacement::Above(anchor),
10935            height: Some(height),
10936            render: Arc::new(move |cx| {
10937                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
10938                cloned_prompt.clone().into_any_element()
10939            }),
10940            priority: 0,
10941        }];
10942
10943        let focus_handle = bp_prompt.focus_handle(cx);
10944        window.focus(&focus_handle);
10945
10946        let block_ids = self.insert_blocks(blocks, None, cx);
10947        bp_prompt.update(cx, |prompt, _| {
10948            prompt.add_block_ids(block_ids);
10949        });
10950    }
10951
10952    pub(crate) fn breakpoint_at_row(
10953        &self,
10954        row: u32,
10955        window: &mut Window,
10956        cx: &mut Context<Self>,
10957    ) -> Option<(Anchor, Breakpoint)> {
10958        let snapshot = self.snapshot(window, cx);
10959        let breakpoint_position = snapshot.buffer_snapshot().anchor_before(Point::new(row, 0));
10960
10961        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10962    }
10963
10964    pub(crate) fn breakpoint_at_anchor(
10965        &self,
10966        breakpoint_position: Anchor,
10967        snapshot: &EditorSnapshot,
10968        cx: &mut Context<Self>,
10969    ) -> Option<(Anchor, Breakpoint)> {
10970        let buffer = self
10971            .buffer
10972            .read(cx)
10973            .buffer_for_anchor(breakpoint_position, cx)?;
10974
10975        let enclosing_excerpt = breakpoint_position.excerpt_id;
10976        let buffer_snapshot = buffer.read(cx).snapshot();
10977
10978        let row = buffer_snapshot
10979            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
10980            .row;
10981
10982        let line_len = snapshot.buffer_snapshot().line_len(MultiBufferRow(row));
10983        let anchor_end = snapshot
10984            .buffer_snapshot()
10985            .anchor_after(Point::new(row, line_len));
10986
10987        self.breakpoint_store
10988            .as_ref()?
10989            .read_with(cx, |breakpoint_store, cx| {
10990                breakpoint_store
10991                    .breakpoints(
10992                        &buffer,
10993                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
10994                        &buffer_snapshot,
10995                        cx,
10996                    )
10997                    .next()
10998                    .and_then(|(bp, _)| {
10999                        let breakpoint_row = buffer_snapshot
11000                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
11001                            .row;
11002
11003                        if breakpoint_row == row {
11004                            snapshot
11005                                .buffer_snapshot()
11006                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
11007                                .map(|position| (position, bp.bp.clone()))
11008                        } else {
11009                            None
11010                        }
11011                    })
11012            })
11013    }
11014
11015    pub fn edit_log_breakpoint(
11016        &mut self,
11017        _: &EditLogBreakpoint,
11018        window: &mut Window,
11019        cx: &mut Context<Self>,
11020    ) {
11021        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11022            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
11023                message: None,
11024                state: BreakpointState::Enabled,
11025                condition: None,
11026                hit_condition: None,
11027            });
11028
11029            self.add_edit_breakpoint_block(
11030                anchor,
11031                &breakpoint,
11032                BreakpointPromptEditAction::Log,
11033                window,
11034                cx,
11035            );
11036        }
11037    }
11038
11039    fn breakpoints_at_cursors(
11040        &self,
11041        window: &mut Window,
11042        cx: &mut Context<Self>,
11043    ) -> Vec<(Anchor, Option<Breakpoint>)> {
11044        let snapshot = self.snapshot(window, cx);
11045        let cursors = self
11046            .selections
11047            .disjoint_anchors_arc()
11048            .iter()
11049            .map(|selection| {
11050                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot());
11051
11052                let breakpoint_position = self
11053                    .breakpoint_at_row(cursor_position.row, window, cx)
11054                    .map(|bp| bp.0)
11055                    .unwrap_or_else(|| {
11056                        snapshot
11057                            .display_snapshot
11058                            .buffer_snapshot()
11059                            .anchor_after(Point::new(cursor_position.row, 0))
11060                    });
11061
11062                let breakpoint = self
11063                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
11064                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
11065
11066                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
11067            })
11068            // 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.
11069            .collect::<HashMap<Anchor, _>>();
11070
11071        cursors.into_iter().collect()
11072    }
11073
11074    pub fn enable_breakpoint(
11075        &mut self,
11076        _: &crate::actions::EnableBreakpoint,
11077        window: &mut Window,
11078        cx: &mut Context<Self>,
11079    ) {
11080        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11081            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
11082                continue;
11083            };
11084            self.edit_breakpoint_at_anchor(
11085                anchor,
11086                breakpoint,
11087                BreakpointEditAction::InvertState,
11088                cx,
11089            );
11090        }
11091    }
11092
11093    pub fn disable_breakpoint(
11094        &mut self,
11095        _: &crate::actions::DisableBreakpoint,
11096        window: &mut Window,
11097        cx: &mut Context<Self>,
11098    ) {
11099        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11100            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
11101                continue;
11102            };
11103            self.edit_breakpoint_at_anchor(
11104                anchor,
11105                breakpoint,
11106                BreakpointEditAction::InvertState,
11107                cx,
11108            );
11109        }
11110    }
11111
11112    pub fn toggle_breakpoint(
11113        &mut self,
11114        _: &crate::actions::ToggleBreakpoint,
11115        window: &mut Window,
11116        cx: &mut Context<Self>,
11117    ) {
11118        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11119            if let Some(breakpoint) = breakpoint {
11120                self.edit_breakpoint_at_anchor(
11121                    anchor,
11122                    breakpoint,
11123                    BreakpointEditAction::Toggle,
11124                    cx,
11125                );
11126            } else {
11127                self.edit_breakpoint_at_anchor(
11128                    anchor,
11129                    Breakpoint::new_standard(),
11130                    BreakpointEditAction::Toggle,
11131                    cx,
11132                );
11133            }
11134        }
11135    }
11136
11137    pub fn edit_breakpoint_at_anchor(
11138        &mut self,
11139        breakpoint_position: Anchor,
11140        breakpoint: Breakpoint,
11141        edit_action: BreakpointEditAction,
11142        cx: &mut Context<Self>,
11143    ) {
11144        let Some(breakpoint_store) = &self.breakpoint_store else {
11145            return;
11146        };
11147
11148        let Some(buffer) = self
11149            .buffer
11150            .read(cx)
11151            .buffer_for_anchor(breakpoint_position, cx)
11152        else {
11153            return;
11154        };
11155
11156        breakpoint_store.update(cx, |breakpoint_store, cx| {
11157            breakpoint_store.toggle_breakpoint(
11158                buffer,
11159                BreakpointWithPosition {
11160                    position: breakpoint_position.text_anchor,
11161                    bp: breakpoint,
11162                },
11163                edit_action,
11164                cx,
11165            );
11166        });
11167
11168        cx.notify();
11169    }
11170
11171    #[cfg(any(test, feature = "test-support"))]
11172    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
11173        self.breakpoint_store.clone()
11174    }
11175
11176    pub fn prepare_restore_change(
11177        &self,
11178        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
11179        hunk: &MultiBufferDiffHunk,
11180        cx: &mut App,
11181    ) -> Option<()> {
11182        if hunk.is_created_file() {
11183            return None;
11184        }
11185        let buffer = self.buffer.read(cx);
11186        let diff = buffer.diff_for(hunk.buffer_id)?;
11187        let buffer = buffer.buffer(hunk.buffer_id)?;
11188        let buffer = buffer.read(cx);
11189        let original_text = diff
11190            .read(cx)
11191            .base_text()
11192            .as_rope()
11193            .slice(hunk.diff_base_byte_range.clone());
11194        let buffer_snapshot = buffer.snapshot();
11195        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
11196        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
11197            probe
11198                .0
11199                .start
11200                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
11201                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
11202        }) {
11203            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
11204            Some(())
11205        } else {
11206            None
11207        }
11208    }
11209
11210    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
11211        self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())
11212    }
11213
11214    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
11215        self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut rand::rng()))
11216    }
11217
11218    fn manipulate_lines<M>(
11219        &mut self,
11220        window: &mut Window,
11221        cx: &mut Context<Self>,
11222        mut manipulate: M,
11223    ) where
11224        M: FnMut(&str) -> LineManipulationResult,
11225    {
11226        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11227
11228        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11229        let buffer = self.buffer.read(cx).snapshot(cx);
11230
11231        let mut edits = Vec::new();
11232
11233        let selections = self.selections.all::<Point>(&display_map);
11234        let mut selections = selections.iter().peekable();
11235        let mut contiguous_row_selections = Vec::new();
11236        let mut new_selections = Vec::new();
11237        let mut added_lines = 0;
11238        let mut removed_lines = 0;
11239
11240        while let Some(selection) = selections.next() {
11241            let (start_row, end_row) = consume_contiguous_rows(
11242                &mut contiguous_row_selections,
11243                selection,
11244                &display_map,
11245                &mut selections,
11246            );
11247
11248            let start_point = Point::new(start_row.0, 0);
11249            let end_point = Point::new(
11250                end_row.previous_row().0,
11251                buffer.line_len(end_row.previous_row()),
11252            );
11253            let text = buffer
11254                .text_for_range(start_point..end_point)
11255                .collect::<String>();
11256
11257            let LineManipulationResult {
11258                new_text,
11259                line_count_before,
11260                line_count_after,
11261            } = manipulate(&text);
11262
11263            edits.push((start_point..end_point, new_text));
11264
11265            // Selections must change based on added and removed line count
11266            let start_row =
11267                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
11268            let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);
11269            new_selections.push(Selection {
11270                id: selection.id,
11271                start: start_row,
11272                end: end_row,
11273                goal: SelectionGoal::None,
11274                reversed: selection.reversed,
11275            });
11276
11277            if line_count_after > line_count_before {
11278                added_lines += line_count_after - line_count_before;
11279            } else if line_count_before > line_count_after {
11280                removed_lines += line_count_before - line_count_after;
11281            }
11282        }
11283
11284        self.transact(window, cx, |this, window, cx| {
11285            let buffer = this.buffer.update(cx, |buffer, cx| {
11286                buffer.edit(edits, None, cx);
11287                buffer.snapshot(cx)
11288            });
11289
11290            // Recalculate offsets on newly edited buffer
11291            let new_selections = new_selections
11292                .iter()
11293                .map(|s| {
11294                    let start_point = Point::new(s.start.0, 0);
11295                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
11296                    Selection {
11297                        id: s.id,
11298                        start: buffer.point_to_offset(start_point),
11299                        end: buffer.point_to_offset(end_point),
11300                        goal: s.goal,
11301                        reversed: s.reversed,
11302                    }
11303                })
11304                .collect();
11305
11306            this.change_selections(Default::default(), window, cx, |s| {
11307                s.select(new_selections);
11308            });
11309
11310            this.request_autoscroll(Autoscroll::fit(), cx);
11311        });
11312    }
11313
11314    fn manipulate_immutable_lines<Fn>(
11315        &mut self,
11316        window: &mut Window,
11317        cx: &mut Context<Self>,
11318        mut callback: Fn,
11319    ) where
11320        Fn: FnMut(&mut Vec<&str>),
11321    {
11322        self.manipulate_lines(window, cx, |text| {
11323            let mut lines: Vec<&str> = text.split('\n').collect();
11324            let line_count_before = lines.len();
11325
11326            callback(&mut lines);
11327
11328            LineManipulationResult {
11329                new_text: lines.join("\n"),
11330                line_count_before,
11331                line_count_after: lines.len(),
11332            }
11333        });
11334    }
11335
11336    fn manipulate_mutable_lines<Fn>(
11337        &mut self,
11338        window: &mut Window,
11339        cx: &mut Context<Self>,
11340        mut callback: Fn,
11341    ) where
11342        Fn: FnMut(&mut Vec<Cow<'_, str>>),
11343    {
11344        self.manipulate_lines(window, cx, |text| {
11345            let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
11346            let line_count_before = lines.len();
11347
11348            callback(&mut lines);
11349
11350            LineManipulationResult {
11351                new_text: lines.join("\n"),
11352                line_count_before,
11353                line_count_after: lines.len(),
11354            }
11355        });
11356    }
11357
11358    pub fn convert_indentation_to_spaces(
11359        &mut self,
11360        _: &ConvertIndentationToSpaces,
11361        window: &mut Window,
11362        cx: &mut Context<Self>,
11363    ) {
11364        let settings = self.buffer.read(cx).language_settings(cx);
11365        let tab_size = settings.tab_size.get() as usize;
11366
11367        self.manipulate_mutable_lines(window, cx, |lines| {
11368            // Allocates a reasonably sized scratch buffer once for the whole loop
11369            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11370            // Avoids recomputing spaces that could be inserted many times
11371            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11372                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11373                .collect();
11374
11375            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11376                let mut chars = line.as_ref().chars();
11377                let mut col = 0;
11378                let mut changed = false;
11379
11380                for ch in chars.by_ref() {
11381                    match ch {
11382                        ' ' => {
11383                            reindented_line.push(' ');
11384                            col += 1;
11385                        }
11386                        '\t' => {
11387                            // \t are converted to spaces depending on the current column
11388                            let spaces_len = tab_size - (col % tab_size);
11389                            reindented_line.extend(&space_cache[spaces_len - 1]);
11390                            col += spaces_len;
11391                            changed = true;
11392                        }
11393                        _ => {
11394                            // If we dont append before break, the character is consumed
11395                            reindented_line.push(ch);
11396                            break;
11397                        }
11398                    }
11399                }
11400
11401                if !changed {
11402                    reindented_line.clear();
11403                    continue;
11404                }
11405                // Append the rest of the line and replace old reference with new one
11406                reindented_line.extend(chars);
11407                *line = Cow::Owned(reindented_line.clone());
11408                reindented_line.clear();
11409            }
11410        });
11411    }
11412
11413    pub fn convert_indentation_to_tabs(
11414        &mut self,
11415        _: &ConvertIndentationToTabs,
11416        window: &mut Window,
11417        cx: &mut Context<Self>,
11418    ) {
11419        let settings = self.buffer.read(cx).language_settings(cx);
11420        let tab_size = settings.tab_size.get() as usize;
11421
11422        self.manipulate_mutable_lines(window, cx, |lines| {
11423            // Allocates a reasonably sized buffer once for the whole loop
11424            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11425            // Avoids recomputing spaces that could be inserted many times
11426            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11427                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11428                .collect();
11429
11430            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11431                let mut chars = line.chars();
11432                let mut spaces_count = 0;
11433                let mut first_non_indent_char = None;
11434                let mut changed = false;
11435
11436                for ch in chars.by_ref() {
11437                    match ch {
11438                        ' ' => {
11439                            // Keep track of spaces. Append \t when we reach tab_size
11440                            spaces_count += 1;
11441                            changed = true;
11442                            if spaces_count == tab_size {
11443                                reindented_line.push('\t');
11444                                spaces_count = 0;
11445                            }
11446                        }
11447                        '\t' => {
11448                            reindented_line.push('\t');
11449                            spaces_count = 0;
11450                        }
11451                        _ => {
11452                            // Dont append it yet, we might have remaining spaces
11453                            first_non_indent_char = Some(ch);
11454                            break;
11455                        }
11456                    }
11457                }
11458
11459                if !changed {
11460                    reindented_line.clear();
11461                    continue;
11462                }
11463                // Remaining spaces that didn't make a full tab stop
11464                if spaces_count > 0 {
11465                    reindented_line.extend(&space_cache[spaces_count - 1]);
11466                }
11467                // If we consume an extra character that was not indentation, add it back
11468                if let Some(extra_char) = first_non_indent_char {
11469                    reindented_line.push(extra_char);
11470                }
11471                // Append the rest of the line and replace old reference with new one
11472                reindented_line.extend(chars);
11473                *line = Cow::Owned(reindented_line.clone());
11474                reindented_line.clear();
11475            }
11476        });
11477    }
11478
11479    pub fn convert_to_upper_case(
11480        &mut self,
11481        _: &ConvertToUpperCase,
11482        window: &mut Window,
11483        cx: &mut Context<Self>,
11484    ) {
11485        self.manipulate_text(window, cx, |text| text.to_uppercase())
11486    }
11487
11488    pub fn convert_to_lower_case(
11489        &mut self,
11490        _: &ConvertToLowerCase,
11491        window: &mut Window,
11492        cx: &mut Context<Self>,
11493    ) {
11494        self.manipulate_text(window, cx, |text| text.to_lowercase())
11495    }
11496
11497    pub fn convert_to_title_case(
11498        &mut self,
11499        _: &ConvertToTitleCase,
11500        window: &mut Window,
11501        cx: &mut Context<Self>,
11502    ) {
11503        self.manipulate_text(window, cx, |text| {
11504            text.split('\n')
11505                .map(|line| line.to_case(Case::Title))
11506                .join("\n")
11507        })
11508    }
11509
11510    pub fn convert_to_snake_case(
11511        &mut self,
11512        _: &ConvertToSnakeCase,
11513        window: &mut Window,
11514        cx: &mut Context<Self>,
11515    ) {
11516        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
11517    }
11518
11519    pub fn convert_to_kebab_case(
11520        &mut self,
11521        _: &ConvertToKebabCase,
11522        window: &mut Window,
11523        cx: &mut Context<Self>,
11524    ) {
11525        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
11526    }
11527
11528    pub fn convert_to_upper_camel_case(
11529        &mut self,
11530        _: &ConvertToUpperCamelCase,
11531        window: &mut Window,
11532        cx: &mut Context<Self>,
11533    ) {
11534        self.manipulate_text(window, cx, |text| {
11535            text.split('\n')
11536                .map(|line| line.to_case(Case::UpperCamel))
11537                .join("\n")
11538        })
11539    }
11540
11541    pub fn convert_to_lower_camel_case(
11542        &mut self,
11543        _: &ConvertToLowerCamelCase,
11544        window: &mut Window,
11545        cx: &mut Context<Self>,
11546    ) {
11547        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
11548    }
11549
11550    pub fn convert_to_opposite_case(
11551        &mut self,
11552        _: &ConvertToOppositeCase,
11553        window: &mut Window,
11554        cx: &mut Context<Self>,
11555    ) {
11556        self.manipulate_text(window, cx, |text| {
11557            text.chars()
11558                .fold(String::with_capacity(text.len()), |mut t, c| {
11559                    if c.is_uppercase() {
11560                        t.extend(c.to_lowercase());
11561                    } else {
11562                        t.extend(c.to_uppercase());
11563                    }
11564                    t
11565                })
11566        })
11567    }
11568
11569    pub fn convert_to_sentence_case(
11570        &mut self,
11571        _: &ConvertToSentenceCase,
11572        window: &mut Window,
11573        cx: &mut Context<Self>,
11574    ) {
11575        self.manipulate_text(window, cx, |text| text.to_case(Case::Sentence))
11576    }
11577
11578    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
11579        self.manipulate_text(window, cx, |text| {
11580            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
11581            if has_upper_case_characters {
11582                text.to_lowercase()
11583            } else {
11584                text.to_uppercase()
11585            }
11586        })
11587    }
11588
11589    pub fn convert_to_rot13(
11590        &mut self,
11591        _: &ConvertToRot13,
11592        window: &mut Window,
11593        cx: &mut Context<Self>,
11594    ) {
11595        self.manipulate_text(window, cx, |text| {
11596            text.chars()
11597                .map(|c| match c {
11598                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
11599                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
11600                    _ => c,
11601                })
11602                .collect()
11603        })
11604    }
11605
11606    pub fn convert_to_rot47(
11607        &mut self,
11608        _: &ConvertToRot47,
11609        window: &mut Window,
11610        cx: &mut Context<Self>,
11611    ) {
11612        self.manipulate_text(window, cx, |text| {
11613            text.chars()
11614                .map(|c| {
11615                    let code_point = c as u32;
11616                    if code_point >= 33 && code_point <= 126 {
11617                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
11618                    }
11619                    c
11620                })
11621                .collect()
11622        })
11623    }
11624
11625    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
11626    where
11627        Fn: FnMut(&str) -> String,
11628    {
11629        let buffer = self.buffer.read(cx).snapshot(cx);
11630
11631        let mut new_selections = Vec::new();
11632        let mut edits = Vec::new();
11633        let mut selection_adjustment = 0i32;
11634
11635        for selection in self.selections.all_adjusted(&self.display_snapshot(cx)) {
11636            let selection_is_empty = selection.is_empty();
11637
11638            let (start, end) = if selection_is_empty {
11639                let (word_range, _) = buffer.surrounding_word(selection.start, None);
11640                (word_range.start, word_range.end)
11641            } else {
11642                (
11643                    buffer.point_to_offset(selection.start),
11644                    buffer.point_to_offset(selection.end),
11645                )
11646            };
11647
11648            let text = buffer.text_for_range(start..end).collect::<String>();
11649            let old_length = text.len() as i32;
11650            let text = callback(&text);
11651
11652            new_selections.push(Selection {
11653                start: (start as i32 - selection_adjustment) as usize,
11654                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
11655                goal: SelectionGoal::None,
11656                id: selection.id,
11657                reversed: selection.reversed,
11658            });
11659
11660            selection_adjustment += old_length - text.len() as i32;
11661
11662            edits.push((start..end, text));
11663        }
11664
11665        self.transact(window, cx, |this, window, cx| {
11666            this.buffer.update(cx, |buffer, cx| {
11667                buffer.edit(edits, None, cx);
11668            });
11669
11670            this.change_selections(Default::default(), window, cx, |s| {
11671                s.select(new_selections);
11672            });
11673
11674            this.request_autoscroll(Autoscroll::fit(), cx);
11675        });
11676    }
11677
11678    pub fn move_selection_on_drop(
11679        &mut self,
11680        selection: &Selection<Anchor>,
11681        target: DisplayPoint,
11682        is_cut: bool,
11683        window: &mut Window,
11684        cx: &mut Context<Self>,
11685    ) {
11686        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11687        let buffer = display_map.buffer_snapshot();
11688        let mut edits = Vec::new();
11689        let insert_point = display_map
11690            .clip_point(target, Bias::Left)
11691            .to_point(&display_map);
11692        let text = buffer
11693            .text_for_range(selection.start..selection.end)
11694            .collect::<String>();
11695        if is_cut {
11696            edits.push(((selection.start..selection.end), String::new()));
11697        }
11698        let insert_anchor = buffer.anchor_before(insert_point);
11699        edits.push(((insert_anchor..insert_anchor), text));
11700        let last_edit_start = insert_anchor.bias_left(buffer);
11701        let last_edit_end = insert_anchor.bias_right(buffer);
11702        self.transact(window, cx, |this, window, cx| {
11703            this.buffer.update(cx, |buffer, cx| {
11704                buffer.edit(edits, None, cx);
11705            });
11706            this.change_selections(Default::default(), window, cx, |s| {
11707                s.select_anchor_ranges([last_edit_start..last_edit_end]);
11708            });
11709        });
11710    }
11711
11712    pub fn clear_selection_drag_state(&mut self) {
11713        self.selection_drag_state = SelectionDragState::None;
11714    }
11715
11716    pub fn duplicate(
11717        &mut self,
11718        upwards: bool,
11719        whole_lines: bool,
11720        window: &mut Window,
11721        cx: &mut Context<Self>,
11722    ) {
11723        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11724
11725        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11726        let buffer = display_map.buffer_snapshot();
11727        let selections = self.selections.all::<Point>(&display_map);
11728
11729        let mut edits = Vec::new();
11730        let mut selections_iter = selections.iter().peekable();
11731        while let Some(selection) = selections_iter.next() {
11732            let mut rows = selection.spanned_rows(false, &display_map);
11733            // duplicate line-wise
11734            if whole_lines || selection.start == selection.end {
11735                // Avoid duplicating the same lines twice.
11736                while let Some(next_selection) = selections_iter.peek() {
11737                    let next_rows = next_selection.spanned_rows(false, &display_map);
11738                    if next_rows.start < rows.end {
11739                        rows.end = next_rows.end;
11740                        selections_iter.next().unwrap();
11741                    } else {
11742                        break;
11743                    }
11744                }
11745
11746                // Copy the text from the selected row region and splice it either at the start
11747                // or end of the region.
11748                let start = Point::new(rows.start.0, 0);
11749                let end = Point::new(
11750                    rows.end.previous_row().0,
11751                    buffer.line_len(rows.end.previous_row()),
11752                );
11753
11754                let mut text = buffer.text_for_range(start..end).collect::<String>();
11755
11756                let insert_location = if upwards {
11757                    // When duplicating upward, we need to insert before the current line.
11758                    // If we're on the last line and it doesn't end with a newline,
11759                    // we need to add a newline before the duplicated content.
11760                    let needs_leading_newline = rows.end.0 >= buffer.max_point().row
11761                        && buffer.max_point().column > 0
11762                        && !text.ends_with('\n');
11763
11764                    if needs_leading_newline {
11765                        text.insert(0, '\n');
11766                        end
11767                    } else {
11768                        text.push('\n');
11769                        Point::new(rows.start.0, 0)
11770                    }
11771                } else {
11772                    text.push('\n');
11773                    start
11774                };
11775                edits.push((insert_location..insert_location, text));
11776            } else {
11777                // duplicate character-wise
11778                let start = selection.start;
11779                let end = selection.end;
11780                let text = buffer.text_for_range(start..end).collect::<String>();
11781                edits.push((selection.end..selection.end, text));
11782            }
11783        }
11784
11785        self.transact(window, cx, |this, window, cx| {
11786            this.buffer.update(cx, |buffer, cx| {
11787                buffer.edit(edits, None, cx);
11788            });
11789
11790            // When duplicating upward with whole lines, move the cursor to the duplicated line
11791            if upwards && whole_lines {
11792                let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
11793
11794                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
11795                    let mut new_ranges = Vec::new();
11796                    let selections = s.all::<Point>(&display_map);
11797                    let mut selections_iter = selections.iter().peekable();
11798
11799                    while let Some(first_selection) = selections_iter.next() {
11800                        // Group contiguous selections together to find the total row span
11801                        let mut group_selections = vec![first_selection];
11802                        let mut rows = first_selection.spanned_rows(false, &display_map);
11803
11804                        while let Some(next_selection) = selections_iter.peek() {
11805                            let next_rows = next_selection.spanned_rows(false, &display_map);
11806                            if next_rows.start < rows.end {
11807                                rows.end = next_rows.end;
11808                                group_selections.push(selections_iter.next().unwrap());
11809                            } else {
11810                                break;
11811                            }
11812                        }
11813
11814                        let row_count = rows.end.0 - rows.start.0;
11815
11816                        // Move all selections in this group up by the total number of duplicated rows
11817                        for selection in group_selections {
11818                            let new_start = Point::new(
11819                                selection.start.row.saturating_sub(row_count),
11820                                selection.start.column,
11821                            );
11822
11823                            let new_end = Point::new(
11824                                selection.end.row.saturating_sub(row_count),
11825                                selection.end.column,
11826                            );
11827
11828                            new_ranges.push(new_start..new_end);
11829                        }
11830                    }
11831
11832                    s.select_ranges(new_ranges);
11833                });
11834            }
11835
11836            this.request_autoscroll(Autoscroll::fit(), cx);
11837        });
11838    }
11839
11840    pub fn duplicate_line_up(
11841        &mut self,
11842        _: &DuplicateLineUp,
11843        window: &mut Window,
11844        cx: &mut Context<Self>,
11845    ) {
11846        self.duplicate(true, true, window, cx);
11847    }
11848
11849    pub fn duplicate_line_down(
11850        &mut self,
11851        _: &DuplicateLineDown,
11852        window: &mut Window,
11853        cx: &mut Context<Self>,
11854    ) {
11855        self.duplicate(false, true, window, cx);
11856    }
11857
11858    pub fn duplicate_selection(
11859        &mut self,
11860        _: &DuplicateSelection,
11861        window: &mut Window,
11862        cx: &mut Context<Self>,
11863    ) {
11864        self.duplicate(false, false, window, cx);
11865    }
11866
11867    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
11868        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11869        if self.mode.is_single_line() {
11870            cx.propagate();
11871            return;
11872        }
11873
11874        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11875        let buffer = self.buffer.read(cx).snapshot(cx);
11876
11877        let mut edits = Vec::new();
11878        let mut unfold_ranges = Vec::new();
11879        let mut refold_creases = Vec::new();
11880
11881        let selections = self.selections.all::<Point>(&display_map);
11882        let mut selections = selections.iter().peekable();
11883        let mut contiguous_row_selections = Vec::new();
11884        let mut new_selections = Vec::new();
11885
11886        while let Some(selection) = selections.next() {
11887            // Find all the selections that span a contiguous row range
11888            let (start_row, end_row) = consume_contiguous_rows(
11889                &mut contiguous_row_selections,
11890                selection,
11891                &display_map,
11892                &mut selections,
11893            );
11894
11895            // Move the text spanned by the row range to be before the line preceding the row range
11896            if start_row.0 > 0 {
11897                let range_to_move = Point::new(
11898                    start_row.previous_row().0,
11899                    buffer.line_len(start_row.previous_row()),
11900                )
11901                    ..Point::new(
11902                        end_row.previous_row().0,
11903                        buffer.line_len(end_row.previous_row()),
11904                    );
11905                let insertion_point = display_map
11906                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
11907                    .0;
11908
11909                // Don't move lines across excerpts
11910                if buffer
11911                    .excerpt_containing(insertion_point..range_to_move.end)
11912                    .is_some()
11913                {
11914                    let text = buffer
11915                        .text_for_range(range_to_move.clone())
11916                        .flat_map(|s| s.chars())
11917                        .skip(1)
11918                        .chain(['\n'])
11919                        .collect::<String>();
11920
11921                    edits.push((
11922                        buffer.anchor_after(range_to_move.start)
11923                            ..buffer.anchor_before(range_to_move.end),
11924                        String::new(),
11925                    ));
11926                    let insertion_anchor = buffer.anchor_after(insertion_point);
11927                    edits.push((insertion_anchor..insertion_anchor, text));
11928
11929                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
11930
11931                    // Move selections up
11932                    new_selections.extend(contiguous_row_selections.drain(..).map(
11933                        |mut selection| {
11934                            selection.start.row -= row_delta;
11935                            selection.end.row -= row_delta;
11936                            selection
11937                        },
11938                    ));
11939
11940                    // Move folds up
11941                    unfold_ranges.push(range_to_move.clone());
11942                    for fold in display_map.folds_in_range(
11943                        buffer.anchor_before(range_to_move.start)
11944                            ..buffer.anchor_after(range_to_move.end),
11945                    ) {
11946                        let mut start = fold.range.start.to_point(&buffer);
11947                        let mut end = fold.range.end.to_point(&buffer);
11948                        start.row -= row_delta;
11949                        end.row -= row_delta;
11950                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11951                    }
11952                }
11953            }
11954
11955            // If we didn't move line(s), preserve the existing selections
11956            new_selections.append(&mut contiguous_row_selections);
11957        }
11958
11959        self.transact(window, cx, |this, window, cx| {
11960            this.unfold_ranges(&unfold_ranges, true, true, cx);
11961            this.buffer.update(cx, |buffer, cx| {
11962                for (range, text) in edits {
11963                    buffer.edit([(range, text)], None, cx);
11964                }
11965            });
11966            this.fold_creases(refold_creases, true, window, cx);
11967            this.change_selections(Default::default(), window, cx, |s| {
11968                s.select(new_selections);
11969            })
11970        });
11971    }
11972
11973    pub fn move_line_down(
11974        &mut self,
11975        _: &MoveLineDown,
11976        window: &mut Window,
11977        cx: &mut Context<Self>,
11978    ) {
11979        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11980        if self.mode.is_single_line() {
11981            cx.propagate();
11982            return;
11983        }
11984
11985        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11986        let buffer = self.buffer.read(cx).snapshot(cx);
11987
11988        let mut edits = Vec::new();
11989        let mut unfold_ranges = Vec::new();
11990        let mut refold_creases = Vec::new();
11991
11992        let selections = self.selections.all::<Point>(&display_map);
11993        let mut selections = selections.iter().peekable();
11994        let mut contiguous_row_selections = Vec::new();
11995        let mut new_selections = Vec::new();
11996
11997        while let Some(selection) = selections.next() {
11998            // Find all the selections that span a contiguous row range
11999            let (start_row, end_row) = consume_contiguous_rows(
12000                &mut contiguous_row_selections,
12001                selection,
12002                &display_map,
12003                &mut selections,
12004            );
12005
12006            // Move the text spanned by the row range to be after the last line of the row range
12007            if end_row.0 <= buffer.max_point().row {
12008                let range_to_move =
12009                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
12010                let insertion_point = display_map
12011                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
12012                    .0;
12013
12014                // Don't move lines across excerpt boundaries
12015                if buffer
12016                    .excerpt_containing(range_to_move.start..insertion_point)
12017                    .is_some()
12018                {
12019                    let mut text = String::from("\n");
12020                    text.extend(buffer.text_for_range(range_to_move.clone()));
12021                    text.pop(); // Drop trailing newline
12022                    edits.push((
12023                        buffer.anchor_after(range_to_move.start)
12024                            ..buffer.anchor_before(range_to_move.end),
12025                        String::new(),
12026                    ));
12027                    let insertion_anchor = buffer.anchor_after(insertion_point);
12028                    edits.push((insertion_anchor..insertion_anchor, text));
12029
12030                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
12031
12032                    // Move selections down
12033                    new_selections.extend(contiguous_row_selections.drain(..).map(
12034                        |mut selection| {
12035                            selection.start.row += row_delta;
12036                            selection.end.row += row_delta;
12037                            selection
12038                        },
12039                    ));
12040
12041                    // Move folds down
12042                    unfold_ranges.push(range_to_move.clone());
12043                    for fold in display_map.folds_in_range(
12044                        buffer.anchor_before(range_to_move.start)
12045                            ..buffer.anchor_after(range_to_move.end),
12046                    ) {
12047                        let mut start = fold.range.start.to_point(&buffer);
12048                        let mut end = fold.range.end.to_point(&buffer);
12049                        start.row += row_delta;
12050                        end.row += row_delta;
12051                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
12052                    }
12053                }
12054            }
12055
12056            // If we didn't move line(s), preserve the existing selections
12057            new_selections.append(&mut contiguous_row_selections);
12058        }
12059
12060        self.transact(window, cx, |this, window, cx| {
12061            this.unfold_ranges(&unfold_ranges, true, true, cx);
12062            this.buffer.update(cx, |buffer, cx| {
12063                for (range, text) in edits {
12064                    buffer.edit([(range, text)], None, cx);
12065                }
12066            });
12067            this.fold_creases(refold_creases, true, window, cx);
12068            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
12069        });
12070    }
12071
12072    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
12073        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12074        let text_layout_details = &self.text_layout_details(window);
12075        self.transact(window, cx, |this, window, cx| {
12076            let edits = this.change_selections(Default::default(), window, cx, |s| {
12077                let mut edits: Vec<(Range<usize>, String)> = Default::default();
12078                s.move_with(|display_map, selection| {
12079                    if !selection.is_empty() {
12080                        return;
12081                    }
12082
12083                    let mut head = selection.head();
12084                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
12085                    if head.column() == display_map.line_len(head.row()) {
12086                        transpose_offset = display_map
12087                            .buffer_snapshot()
12088                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
12089                    }
12090
12091                    if transpose_offset == 0 {
12092                        return;
12093                    }
12094
12095                    *head.column_mut() += 1;
12096                    head = display_map.clip_point(head, Bias::Right);
12097                    let goal = SelectionGoal::HorizontalPosition(
12098                        display_map
12099                            .x_for_display_point(head, text_layout_details)
12100                            .into(),
12101                    );
12102                    selection.collapse_to(head, goal);
12103
12104                    let transpose_start = display_map
12105                        .buffer_snapshot()
12106                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
12107                    if edits.last().is_none_or(|e| e.0.end <= transpose_start) {
12108                        let transpose_end = display_map
12109                            .buffer_snapshot()
12110                            .clip_offset(transpose_offset + 1, Bias::Right);
12111                        if let Some(ch) = display_map
12112                            .buffer_snapshot()
12113                            .chars_at(transpose_start)
12114                            .next()
12115                        {
12116                            edits.push((transpose_start..transpose_offset, String::new()));
12117                            edits.push((transpose_end..transpose_end, ch.to_string()));
12118                        }
12119                    }
12120                });
12121                edits
12122            });
12123            this.buffer
12124                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12125            let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
12126            this.change_selections(Default::default(), window, cx, |s| {
12127                s.select(selections);
12128            });
12129        });
12130    }
12131
12132    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
12133        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12134        if self.mode.is_single_line() {
12135            cx.propagate();
12136            return;
12137        }
12138
12139        self.rewrap_impl(RewrapOptions::default(), cx)
12140    }
12141
12142    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
12143        let buffer = self.buffer.read(cx).snapshot(cx);
12144        let selections = self.selections.all::<Point>(&self.display_snapshot(cx));
12145
12146        #[derive(Clone, Debug, PartialEq)]
12147        enum CommentFormat {
12148            /// single line comment, with prefix for line
12149            Line(String),
12150            /// single line within a block comment, with prefix for line
12151            BlockLine(String),
12152            /// a single line of a block comment that includes the initial delimiter
12153            BlockCommentWithStart(BlockCommentConfig),
12154            /// a single line of a block comment that includes the ending delimiter
12155            BlockCommentWithEnd(BlockCommentConfig),
12156        }
12157
12158        // Split selections to respect paragraph, indent, and comment prefix boundaries.
12159        let wrap_ranges = selections.into_iter().flat_map(|selection| {
12160            let mut non_blank_rows_iter = (selection.start.row..=selection.end.row)
12161                .filter(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
12162                .peekable();
12163
12164            let first_row = if let Some(&row) = non_blank_rows_iter.peek() {
12165                row
12166            } else {
12167                return Vec::new();
12168            };
12169
12170            let language_settings = buffer.language_settings_at(selection.head(), cx);
12171            let language_scope = buffer.language_scope_at(selection.head());
12172
12173            let indent_and_prefix_for_row =
12174                |row: u32| -> (IndentSize, Option<CommentFormat>, Option<String>) {
12175                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
12176                    let (comment_prefix, rewrap_prefix) = if let Some(language_scope) =
12177                        &language_scope
12178                    {
12179                        let indent_end = Point::new(row, indent.len);
12180                        let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
12181                        let line_text_after_indent = buffer
12182                            .text_for_range(indent_end..line_end)
12183                            .collect::<String>();
12184
12185                        let is_within_comment_override = buffer
12186                            .language_scope_at(indent_end)
12187                            .is_some_and(|scope| scope.override_name() == Some("comment"));
12188                        let comment_delimiters = if is_within_comment_override {
12189                            // we are within a comment syntax node, but we don't
12190                            // yet know what kind of comment: block, doc or line
12191                            match (
12192                                language_scope.documentation_comment(),
12193                                language_scope.block_comment(),
12194                            ) {
12195                                (Some(config), _) | (_, Some(config))
12196                                    if buffer.contains_str_at(indent_end, &config.start) =>
12197                                {
12198                                    Some(CommentFormat::BlockCommentWithStart(config.clone()))
12199                                }
12200                                (Some(config), _) | (_, Some(config))
12201                                    if line_text_after_indent.ends_with(config.end.as_ref()) =>
12202                                {
12203                                    Some(CommentFormat::BlockCommentWithEnd(config.clone()))
12204                                }
12205                                (Some(config), _) | (_, Some(config))
12206                                    if buffer.contains_str_at(indent_end, &config.prefix) =>
12207                                {
12208                                    Some(CommentFormat::BlockLine(config.prefix.to_string()))
12209                                }
12210                                (_, _) => language_scope
12211                                    .line_comment_prefixes()
12212                                    .iter()
12213                                    .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12214                                    .map(|prefix| CommentFormat::Line(prefix.to_string())),
12215                            }
12216                        } else {
12217                            // we not in an overridden comment node, but we may
12218                            // be within a non-overridden line comment node
12219                            language_scope
12220                                .line_comment_prefixes()
12221                                .iter()
12222                                .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12223                                .map(|prefix| CommentFormat::Line(prefix.to_string()))
12224                        };
12225
12226                        let rewrap_prefix = language_scope
12227                            .rewrap_prefixes()
12228                            .iter()
12229                            .find_map(|prefix_regex| {
12230                                prefix_regex.find(&line_text_after_indent).map(|mat| {
12231                                    if mat.start() == 0 {
12232                                        Some(mat.as_str().to_string())
12233                                    } else {
12234                                        None
12235                                    }
12236                                })
12237                            })
12238                            .flatten();
12239                        (comment_delimiters, rewrap_prefix)
12240                    } else {
12241                        (None, None)
12242                    };
12243                    (indent, comment_prefix, rewrap_prefix)
12244                };
12245
12246            let mut ranges = Vec::new();
12247            let from_empty_selection = selection.is_empty();
12248
12249            let mut current_range_start = first_row;
12250            let mut prev_row = first_row;
12251            let (
12252                mut current_range_indent,
12253                mut current_range_comment_delimiters,
12254                mut current_range_rewrap_prefix,
12255            ) = indent_and_prefix_for_row(first_row);
12256
12257            for row in non_blank_rows_iter.skip(1) {
12258                let has_paragraph_break = row > prev_row + 1;
12259
12260                let (row_indent, row_comment_delimiters, row_rewrap_prefix) =
12261                    indent_and_prefix_for_row(row);
12262
12263                let has_indent_change = row_indent != current_range_indent;
12264                let has_comment_change = row_comment_delimiters != current_range_comment_delimiters;
12265
12266                let has_boundary_change = has_comment_change
12267                    || row_rewrap_prefix.is_some()
12268                    || (has_indent_change && current_range_comment_delimiters.is_some());
12269
12270                if has_paragraph_break || has_boundary_change {
12271                    ranges.push((
12272                        language_settings.clone(),
12273                        Point::new(current_range_start, 0)
12274                            ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12275                        current_range_indent,
12276                        current_range_comment_delimiters.clone(),
12277                        current_range_rewrap_prefix.clone(),
12278                        from_empty_selection,
12279                    ));
12280                    current_range_start = row;
12281                    current_range_indent = row_indent;
12282                    current_range_comment_delimiters = row_comment_delimiters;
12283                    current_range_rewrap_prefix = row_rewrap_prefix;
12284                }
12285                prev_row = row;
12286            }
12287
12288            ranges.push((
12289                language_settings.clone(),
12290                Point::new(current_range_start, 0)
12291                    ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12292                current_range_indent,
12293                current_range_comment_delimiters,
12294                current_range_rewrap_prefix,
12295                from_empty_selection,
12296            ));
12297
12298            ranges
12299        });
12300
12301        let mut edits = Vec::new();
12302        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
12303
12304        for (
12305            language_settings,
12306            wrap_range,
12307            mut indent_size,
12308            comment_prefix,
12309            rewrap_prefix,
12310            from_empty_selection,
12311        ) in wrap_ranges
12312        {
12313            let mut start_row = wrap_range.start.row;
12314            let mut end_row = wrap_range.end.row;
12315
12316            // Skip selections that overlap with a range that has already been rewrapped.
12317            let selection_range = start_row..end_row;
12318            if rewrapped_row_ranges
12319                .iter()
12320                .any(|range| range.overlaps(&selection_range))
12321            {
12322                continue;
12323            }
12324
12325            let tab_size = language_settings.tab_size;
12326
12327            let (line_prefix, inside_comment) = match &comment_prefix {
12328                Some(CommentFormat::Line(prefix) | CommentFormat::BlockLine(prefix)) => {
12329                    (Some(prefix.as_str()), true)
12330                }
12331                Some(CommentFormat::BlockCommentWithEnd(BlockCommentConfig { prefix, .. })) => {
12332                    (Some(prefix.as_ref()), true)
12333                }
12334                Some(CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12335                    start: _,
12336                    end: _,
12337                    prefix,
12338                    tab_size,
12339                })) => {
12340                    indent_size.len += tab_size;
12341                    (Some(prefix.as_ref()), true)
12342                }
12343                None => (None, false),
12344            };
12345            let indent_prefix = indent_size.chars().collect::<String>();
12346            let line_prefix = format!("{indent_prefix}{}", line_prefix.unwrap_or(""));
12347
12348            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
12349                RewrapBehavior::InComments => inside_comment,
12350                RewrapBehavior::InSelections => !wrap_range.is_empty(),
12351                RewrapBehavior::Anywhere => true,
12352            };
12353
12354            let should_rewrap = options.override_language_settings
12355                || allow_rewrap_based_on_language
12356                || self.hard_wrap.is_some();
12357            if !should_rewrap {
12358                continue;
12359            }
12360
12361            if from_empty_selection {
12362                'expand_upwards: while start_row > 0 {
12363                    let prev_row = start_row - 1;
12364                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
12365                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
12366                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
12367                    {
12368                        start_row = prev_row;
12369                    } else {
12370                        break 'expand_upwards;
12371                    }
12372                }
12373
12374                'expand_downwards: while end_row < buffer.max_point().row {
12375                    let next_row = end_row + 1;
12376                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
12377                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
12378                        && !buffer.is_line_blank(MultiBufferRow(next_row))
12379                    {
12380                        end_row = next_row;
12381                    } else {
12382                        break 'expand_downwards;
12383                    }
12384                }
12385            }
12386
12387            let start = Point::new(start_row, 0);
12388            let start_offset = ToOffset::to_offset(&start, &buffer);
12389            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
12390            let selection_text = buffer.text_for_range(start..end).collect::<String>();
12391            let mut first_line_delimiter = None;
12392            let mut last_line_delimiter = None;
12393            let Some(lines_without_prefixes) = selection_text
12394                .lines()
12395                .enumerate()
12396                .map(|(ix, line)| {
12397                    let line_trimmed = line.trim_start();
12398                    if rewrap_prefix.is_some() && ix > 0 {
12399                        Ok(line_trimmed)
12400                    } else if let Some(
12401                        CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12402                            start,
12403                            prefix,
12404                            end,
12405                            tab_size,
12406                        })
12407                        | CommentFormat::BlockCommentWithEnd(BlockCommentConfig {
12408                            start,
12409                            prefix,
12410                            end,
12411                            tab_size,
12412                        }),
12413                    ) = &comment_prefix
12414                    {
12415                        let line_trimmed = line_trimmed
12416                            .strip_prefix(start.as_ref())
12417                            .map(|s| {
12418                                let mut indent_size = indent_size;
12419                                indent_size.len -= tab_size;
12420                                let indent_prefix: String = indent_size.chars().collect();
12421                                first_line_delimiter = Some((indent_prefix, start));
12422                                s.trim_start()
12423                            })
12424                            .unwrap_or(line_trimmed);
12425                        let line_trimmed = line_trimmed
12426                            .strip_suffix(end.as_ref())
12427                            .map(|s| {
12428                                last_line_delimiter = Some(end);
12429                                s.trim_end()
12430                            })
12431                            .unwrap_or(line_trimmed);
12432                        let line_trimmed = line_trimmed
12433                            .strip_prefix(prefix.as_ref())
12434                            .unwrap_or(line_trimmed);
12435                        Ok(line_trimmed)
12436                    } else if let Some(CommentFormat::BlockLine(prefix)) = &comment_prefix {
12437                        line_trimmed.strip_prefix(prefix).with_context(|| {
12438                            format!("line did not start with prefix {prefix:?}: {line:?}")
12439                        })
12440                    } else {
12441                        line_trimmed
12442                            .strip_prefix(&line_prefix.trim_start())
12443                            .with_context(|| {
12444                                format!("line did not start with prefix {line_prefix:?}: {line:?}")
12445                            })
12446                    }
12447                })
12448                .collect::<Result<Vec<_>, _>>()
12449                .log_err()
12450            else {
12451                continue;
12452            };
12453
12454            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
12455                buffer
12456                    .language_settings_at(Point::new(start_row, 0), cx)
12457                    .preferred_line_length as usize
12458            });
12459
12460            let subsequent_lines_prefix = if let Some(rewrap_prefix_str) = &rewrap_prefix {
12461                format!("{}{}", indent_prefix, " ".repeat(rewrap_prefix_str.len()))
12462            } else {
12463                line_prefix.clone()
12464            };
12465
12466            let wrapped_text = {
12467                let mut wrapped_text = wrap_with_prefix(
12468                    line_prefix,
12469                    subsequent_lines_prefix,
12470                    lines_without_prefixes.join("\n"),
12471                    wrap_column,
12472                    tab_size,
12473                    options.preserve_existing_whitespace,
12474                );
12475
12476                if let Some((indent, delimiter)) = first_line_delimiter {
12477                    wrapped_text = format!("{indent}{delimiter}\n{wrapped_text}");
12478                }
12479                if let Some(last_line) = last_line_delimiter {
12480                    wrapped_text = format!("{wrapped_text}\n{indent_prefix}{last_line}");
12481                }
12482
12483                wrapped_text
12484            };
12485
12486            // TODO: should always use char-based diff while still supporting cursor behavior that
12487            // matches vim.
12488            let mut diff_options = DiffOptions::default();
12489            if options.override_language_settings {
12490                diff_options.max_word_diff_len = 0;
12491                diff_options.max_word_diff_line_count = 0;
12492            } else {
12493                diff_options.max_word_diff_len = usize::MAX;
12494                diff_options.max_word_diff_line_count = usize::MAX;
12495            }
12496
12497            for (old_range, new_text) in
12498                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
12499            {
12500                let edit_start = buffer.anchor_after(start_offset + old_range.start);
12501                let edit_end = buffer.anchor_after(start_offset + old_range.end);
12502                edits.push((edit_start..edit_end, new_text));
12503            }
12504
12505            rewrapped_row_ranges.push(start_row..=end_row);
12506        }
12507
12508        self.buffer
12509            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12510    }
12511
12512    pub fn cut_common(
12513        &mut self,
12514        cut_no_selection_line: bool,
12515        window: &mut Window,
12516        cx: &mut Context<Self>,
12517    ) -> ClipboardItem {
12518        let mut text = String::new();
12519        let buffer = self.buffer.read(cx).snapshot(cx);
12520        let mut selections = self.selections.all::<Point>(&self.display_snapshot(cx));
12521        let mut clipboard_selections = Vec::with_capacity(selections.len());
12522        {
12523            let max_point = buffer.max_point();
12524            let mut is_first = true;
12525            for selection in &mut selections {
12526                let is_entire_line =
12527                    (selection.is_empty() && cut_no_selection_line) || self.selections.line_mode();
12528                if is_entire_line {
12529                    selection.start = Point::new(selection.start.row, 0);
12530                    if !selection.is_empty() && selection.end.column == 0 {
12531                        selection.end = cmp::min(max_point, selection.end);
12532                    } else {
12533                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
12534                    }
12535                    selection.goal = SelectionGoal::None;
12536                }
12537                if is_first {
12538                    is_first = false;
12539                } else {
12540                    text += "\n";
12541                }
12542                let mut len = 0;
12543                for chunk in buffer.text_for_range(selection.start..selection.end) {
12544                    text.push_str(chunk);
12545                    len += chunk.len();
12546                }
12547                clipboard_selections.push(ClipboardSelection {
12548                    len,
12549                    is_entire_line,
12550                    first_line_indent: buffer
12551                        .indent_size_for_line(MultiBufferRow(selection.start.row))
12552                        .len,
12553                });
12554            }
12555        }
12556
12557        self.transact(window, cx, |this, window, cx| {
12558            this.change_selections(Default::default(), window, cx, |s| {
12559                s.select(selections);
12560            });
12561            this.insert("", window, cx);
12562        });
12563        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
12564    }
12565
12566    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
12567        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12568        let item = self.cut_common(true, window, cx);
12569        cx.write_to_clipboard(item);
12570    }
12571
12572    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
12573        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12574        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12575            s.move_with(|snapshot, sel| {
12576                if sel.is_empty() {
12577                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()));
12578                }
12579                if sel.is_empty() {
12580                    sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
12581                }
12582            });
12583        });
12584        let item = self.cut_common(false, window, cx);
12585        cx.set_global(KillRing(item))
12586    }
12587
12588    pub fn kill_ring_yank(
12589        &mut self,
12590        _: &KillRingYank,
12591        window: &mut Window,
12592        cx: &mut Context<Self>,
12593    ) {
12594        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12595        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
12596            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
12597                (kill_ring.text().to_string(), kill_ring.metadata_json())
12598            } else {
12599                return;
12600            }
12601        } else {
12602            return;
12603        };
12604        self.do_paste(&text, metadata, false, window, cx);
12605    }
12606
12607    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
12608        self.do_copy(true, cx);
12609    }
12610
12611    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
12612        self.do_copy(false, cx);
12613    }
12614
12615    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
12616        let selections = self.selections.all::<Point>(&self.display_snapshot(cx));
12617        let buffer = self.buffer.read(cx).read(cx);
12618        let mut text = String::new();
12619
12620        let mut clipboard_selections = Vec::with_capacity(selections.len());
12621        {
12622            let max_point = buffer.max_point();
12623            let mut is_first = true;
12624            for selection in &selections {
12625                let mut start = selection.start;
12626                let mut end = selection.end;
12627                let is_entire_line = selection.is_empty() || self.selections.line_mode();
12628                let mut add_trailing_newline = false;
12629                if is_entire_line {
12630                    start = Point::new(start.row, 0);
12631                    let next_line_start = Point::new(end.row + 1, 0);
12632                    if next_line_start <= max_point {
12633                        end = next_line_start;
12634                    } else {
12635                        // We're on the last line without a trailing newline.
12636                        // Copy to the end of the line and add a newline afterwards.
12637                        end = Point::new(end.row, buffer.line_len(MultiBufferRow(end.row)));
12638                        add_trailing_newline = true;
12639                    }
12640                }
12641
12642                let mut trimmed_selections = Vec::new();
12643                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
12644                    let row = MultiBufferRow(start.row);
12645                    let first_indent = buffer.indent_size_for_line(row);
12646                    if first_indent.len == 0 || start.column > first_indent.len {
12647                        trimmed_selections.push(start..end);
12648                    } else {
12649                        trimmed_selections.push(
12650                            Point::new(row.0, first_indent.len)
12651                                ..Point::new(row.0, buffer.line_len(row)),
12652                        );
12653                        for row in start.row + 1..=end.row {
12654                            let mut line_len = buffer.line_len(MultiBufferRow(row));
12655                            if row == end.row {
12656                                line_len = end.column;
12657                            }
12658                            if line_len == 0 {
12659                                trimmed_selections
12660                                    .push(Point::new(row, 0)..Point::new(row, line_len));
12661                                continue;
12662                            }
12663                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
12664                            if row_indent_size.len >= first_indent.len {
12665                                trimmed_selections.push(
12666                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
12667                                );
12668                            } else {
12669                                trimmed_selections.clear();
12670                                trimmed_selections.push(start..end);
12671                                break;
12672                            }
12673                        }
12674                    }
12675                } else {
12676                    trimmed_selections.push(start..end);
12677                }
12678
12679                for trimmed_range in trimmed_selections {
12680                    if is_first {
12681                        is_first = false;
12682                    } else {
12683                        text += "\n";
12684                    }
12685                    let mut len = 0;
12686                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
12687                        text.push_str(chunk);
12688                        len += chunk.len();
12689                    }
12690                    if add_trailing_newline {
12691                        text.push('\n');
12692                        len += 1;
12693                    }
12694                    clipboard_selections.push(ClipboardSelection {
12695                        len,
12696                        is_entire_line,
12697                        first_line_indent: buffer
12698                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
12699                            .len,
12700                    });
12701                }
12702            }
12703        }
12704
12705        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
12706            text,
12707            clipboard_selections,
12708        ));
12709    }
12710
12711    pub fn do_paste(
12712        &mut self,
12713        text: &String,
12714        clipboard_selections: Option<Vec<ClipboardSelection>>,
12715        handle_entire_lines: bool,
12716        window: &mut Window,
12717        cx: &mut Context<Self>,
12718    ) {
12719        if self.read_only(cx) {
12720            return;
12721        }
12722
12723        let clipboard_text = Cow::Borrowed(text.as_str());
12724
12725        self.transact(window, cx, |this, window, cx| {
12726            let had_active_edit_prediction = this.has_active_edit_prediction();
12727            let display_map = this.display_snapshot(cx);
12728            let old_selections = this.selections.all::<usize>(&display_map);
12729            let cursor_offset = this.selections.last::<usize>(&display_map).head();
12730
12731            if let Some(mut clipboard_selections) = clipboard_selections {
12732                let all_selections_were_entire_line =
12733                    clipboard_selections.iter().all(|s| s.is_entire_line);
12734                let first_selection_indent_column =
12735                    clipboard_selections.first().map(|s| s.first_line_indent);
12736                if clipboard_selections.len() != old_selections.len() {
12737                    clipboard_selections.drain(..);
12738                }
12739                let mut auto_indent_on_paste = true;
12740
12741                this.buffer.update(cx, |buffer, cx| {
12742                    let snapshot = buffer.read(cx);
12743                    auto_indent_on_paste = snapshot
12744                        .language_settings_at(cursor_offset, cx)
12745                        .auto_indent_on_paste;
12746
12747                    let mut start_offset = 0;
12748                    let mut edits = Vec::new();
12749                    let mut original_indent_columns = Vec::new();
12750                    for (ix, selection) in old_selections.iter().enumerate() {
12751                        let to_insert;
12752                        let entire_line;
12753                        let original_indent_column;
12754                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
12755                            let end_offset = start_offset + clipboard_selection.len;
12756                            to_insert = &clipboard_text[start_offset..end_offset];
12757                            entire_line = clipboard_selection.is_entire_line;
12758                            start_offset = end_offset + 1;
12759                            original_indent_column = Some(clipboard_selection.first_line_indent);
12760                        } else {
12761                            to_insert = &*clipboard_text;
12762                            entire_line = all_selections_were_entire_line;
12763                            original_indent_column = first_selection_indent_column
12764                        }
12765
12766                        let (range, to_insert) =
12767                            if selection.is_empty() && handle_entire_lines && entire_line {
12768                                // If the corresponding selection was empty when this slice of the
12769                                // clipboard text was written, then the entire line containing the
12770                                // selection was copied. If this selection is also currently empty,
12771                                // then paste the line before the current line of the buffer.
12772                                let column = selection.start.to_point(&snapshot).column as usize;
12773                                let line_start = selection.start - column;
12774                                (line_start..line_start, Cow::Borrowed(to_insert))
12775                            } else {
12776                                let language = snapshot.language_at(selection.head());
12777                                let range = selection.range();
12778                                if let Some(language) = language
12779                                    && language.name() == "Markdown".into()
12780                                {
12781                                    edit_for_markdown_paste(
12782                                        &snapshot,
12783                                        range,
12784                                        to_insert,
12785                                        url::Url::parse(to_insert).ok(),
12786                                    )
12787                                } else {
12788                                    (range, Cow::Borrowed(to_insert))
12789                                }
12790                            };
12791
12792                        edits.push((range, to_insert));
12793                        original_indent_columns.push(original_indent_column);
12794                    }
12795                    drop(snapshot);
12796
12797                    buffer.edit(
12798                        edits,
12799                        if auto_indent_on_paste {
12800                            Some(AutoindentMode::Block {
12801                                original_indent_columns,
12802                            })
12803                        } else {
12804                            None
12805                        },
12806                        cx,
12807                    );
12808                });
12809
12810                let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
12811                this.change_selections(Default::default(), window, cx, |s| s.select(selections));
12812            } else {
12813                let url = url::Url::parse(&clipboard_text).ok();
12814
12815                let auto_indent_mode = if !clipboard_text.is_empty() {
12816                    Some(AutoindentMode::Block {
12817                        original_indent_columns: Vec::new(),
12818                    })
12819                } else {
12820                    None
12821                };
12822
12823                let selection_anchors = this.buffer.update(cx, |buffer, cx| {
12824                    let snapshot = buffer.snapshot(cx);
12825
12826                    let anchors = old_selections
12827                        .iter()
12828                        .map(|s| {
12829                            let anchor = snapshot.anchor_after(s.head());
12830                            s.map(|_| anchor)
12831                        })
12832                        .collect::<Vec<_>>();
12833
12834                    let mut edits = Vec::new();
12835
12836                    for selection in old_selections.iter() {
12837                        let language = snapshot.language_at(selection.head());
12838                        let range = selection.range();
12839
12840                        let (edit_range, edit_text) = if let Some(language) = language
12841                            && language.name() == "Markdown".into()
12842                        {
12843                            edit_for_markdown_paste(&snapshot, range, &clipboard_text, url.clone())
12844                        } else {
12845                            (range, clipboard_text.clone())
12846                        };
12847
12848                        edits.push((edit_range, edit_text));
12849                    }
12850
12851                    drop(snapshot);
12852                    buffer.edit(edits, auto_indent_mode, cx);
12853
12854                    anchors
12855                });
12856
12857                this.change_selections(Default::default(), window, cx, |s| {
12858                    s.select_anchors(selection_anchors);
12859                });
12860            }
12861
12862            //   🤔                 |    ..     | show_in_menu |
12863            // | ..                  |   true        true
12864            // | had_edit_prediction |   false       true
12865
12866            let trigger_in_words =
12867                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
12868
12869            this.trigger_completion_on_input(text, trigger_in_words, window, cx);
12870        });
12871    }
12872
12873    pub fn diff_clipboard_with_selection(
12874        &mut self,
12875        _: &DiffClipboardWithSelection,
12876        window: &mut Window,
12877        cx: &mut Context<Self>,
12878    ) {
12879        let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
12880
12881        if selections.is_empty() {
12882            log::warn!("There should always be at least one selection in Zed. This is a bug.");
12883            return;
12884        };
12885
12886        let clipboard_text = match cx.read_from_clipboard() {
12887            Some(item) => match item.entries().first() {
12888                Some(ClipboardEntry::String(text)) => Some(text.text().to_string()),
12889                _ => None,
12890            },
12891            None => None,
12892        };
12893
12894        let Some(clipboard_text) = clipboard_text else {
12895            log::warn!("Clipboard doesn't contain text.");
12896            return;
12897        };
12898
12899        window.dispatch_action(
12900            Box::new(DiffClipboardWithSelectionData {
12901                clipboard_text,
12902                editor: cx.entity(),
12903            }),
12904            cx,
12905        );
12906    }
12907
12908    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
12909        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12910        if let Some(item) = cx.read_from_clipboard() {
12911            let entries = item.entries();
12912
12913            match entries.first() {
12914                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
12915                // of all the pasted entries.
12916                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
12917                    .do_paste(
12918                        clipboard_string.text(),
12919                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
12920                        true,
12921                        window,
12922                        cx,
12923                    ),
12924                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
12925            }
12926        }
12927    }
12928
12929    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
12930        if self.read_only(cx) {
12931            return;
12932        }
12933
12934        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12935
12936        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
12937            if let Some((selections, _)) =
12938                self.selection_history.transaction(transaction_id).cloned()
12939            {
12940                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12941                    s.select_anchors(selections.to_vec());
12942                });
12943            } else {
12944                log::error!(
12945                    "No entry in selection_history found for undo. \
12946                     This may correspond to a bug where undo does not update the selection. \
12947                     If this is occurring, please add details to \
12948                     https://github.com/zed-industries/zed/issues/22692"
12949                );
12950            }
12951            self.request_autoscroll(Autoscroll::fit(), cx);
12952            self.unmark_text(window, cx);
12953            self.refresh_edit_prediction(true, false, window, cx);
12954            cx.emit(EditorEvent::Edited { transaction_id });
12955            cx.emit(EditorEvent::TransactionUndone { transaction_id });
12956        }
12957    }
12958
12959    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
12960        if self.read_only(cx) {
12961            return;
12962        }
12963
12964        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12965
12966        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
12967            if let Some((_, Some(selections))) =
12968                self.selection_history.transaction(transaction_id).cloned()
12969            {
12970                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12971                    s.select_anchors(selections.to_vec());
12972                });
12973            } else {
12974                log::error!(
12975                    "No entry in selection_history found for redo. \
12976                     This may correspond to a bug where undo does not update the selection. \
12977                     If this is occurring, please add details to \
12978                     https://github.com/zed-industries/zed/issues/22692"
12979                );
12980            }
12981            self.request_autoscroll(Autoscroll::fit(), cx);
12982            self.unmark_text(window, cx);
12983            self.refresh_edit_prediction(true, false, window, cx);
12984            cx.emit(EditorEvent::Edited { transaction_id });
12985        }
12986    }
12987
12988    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
12989        self.buffer
12990            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
12991    }
12992
12993    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
12994        self.buffer
12995            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
12996    }
12997
12998    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
12999        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13000        self.change_selections(Default::default(), window, cx, |s| {
13001            s.move_with(|map, selection| {
13002                let cursor = if selection.is_empty() {
13003                    movement::left(map, selection.start)
13004                } else {
13005                    selection.start
13006                };
13007                selection.collapse_to(cursor, SelectionGoal::None);
13008            });
13009        })
13010    }
13011
13012    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
13013        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13014        self.change_selections(Default::default(), window, cx, |s| {
13015            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
13016        })
13017    }
13018
13019    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
13020        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13021        self.change_selections(Default::default(), window, cx, |s| {
13022            s.move_with(|map, selection| {
13023                let cursor = if selection.is_empty() {
13024                    movement::right(map, selection.end)
13025                } else {
13026                    selection.end
13027                };
13028                selection.collapse_to(cursor, SelectionGoal::None)
13029            });
13030        })
13031    }
13032
13033    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
13034        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13035        self.change_selections(Default::default(), window, cx, |s| {
13036            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
13037        });
13038    }
13039
13040    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
13041        if self.take_rename(true, window, cx).is_some() {
13042            return;
13043        }
13044
13045        if self.mode.is_single_line() {
13046            cx.propagate();
13047            return;
13048        }
13049
13050        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13051
13052        let text_layout_details = &self.text_layout_details(window);
13053        let selection_count = self.selections.count();
13054        let first_selection = self.selections.first_anchor();
13055
13056        self.change_selections(Default::default(), window, cx, |s| {
13057            s.move_with(|map, selection| {
13058                if !selection.is_empty() {
13059                    selection.goal = SelectionGoal::None;
13060                }
13061                let (cursor, goal) = movement::up(
13062                    map,
13063                    selection.start,
13064                    selection.goal,
13065                    false,
13066                    text_layout_details,
13067                );
13068                selection.collapse_to(cursor, goal);
13069            });
13070        });
13071
13072        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
13073        {
13074            cx.propagate();
13075        }
13076    }
13077
13078    pub fn move_up_by_lines(
13079        &mut self,
13080        action: &MoveUpByLines,
13081        window: &mut Window,
13082        cx: &mut Context<Self>,
13083    ) {
13084        if self.take_rename(true, window, cx).is_some() {
13085            return;
13086        }
13087
13088        if self.mode.is_single_line() {
13089            cx.propagate();
13090            return;
13091        }
13092
13093        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13094
13095        let text_layout_details = &self.text_layout_details(window);
13096
13097        self.change_selections(Default::default(), window, cx, |s| {
13098            s.move_with(|map, selection| {
13099                if !selection.is_empty() {
13100                    selection.goal = SelectionGoal::None;
13101                }
13102                let (cursor, goal) = movement::up_by_rows(
13103                    map,
13104                    selection.start,
13105                    action.lines,
13106                    selection.goal,
13107                    false,
13108                    text_layout_details,
13109                );
13110                selection.collapse_to(cursor, goal);
13111            });
13112        })
13113    }
13114
13115    pub fn move_down_by_lines(
13116        &mut self,
13117        action: &MoveDownByLines,
13118        window: &mut Window,
13119        cx: &mut Context<Self>,
13120    ) {
13121        if self.take_rename(true, window, cx).is_some() {
13122            return;
13123        }
13124
13125        if self.mode.is_single_line() {
13126            cx.propagate();
13127            return;
13128        }
13129
13130        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13131
13132        let text_layout_details = &self.text_layout_details(window);
13133
13134        self.change_selections(Default::default(), window, cx, |s| {
13135            s.move_with(|map, selection| {
13136                if !selection.is_empty() {
13137                    selection.goal = SelectionGoal::None;
13138                }
13139                let (cursor, goal) = movement::down_by_rows(
13140                    map,
13141                    selection.start,
13142                    action.lines,
13143                    selection.goal,
13144                    false,
13145                    text_layout_details,
13146                );
13147                selection.collapse_to(cursor, goal);
13148            });
13149        })
13150    }
13151
13152    pub fn select_down_by_lines(
13153        &mut self,
13154        action: &SelectDownByLines,
13155        window: &mut Window,
13156        cx: &mut Context<Self>,
13157    ) {
13158        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13159        let text_layout_details = &self.text_layout_details(window);
13160        self.change_selections(Default::default(), window, cx, |s| {
13161            s.move_heads_with(|map, head, goal| {
13162                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
13163            })
13164        })
13165    }
13166
13167    pub fn select_up_by_lines(
13168        &mut self,
13169        action: &SelectUpByLines,
13170        window: &mut Window,
13171        cx: &mut Context<Self>,
13172    ) {
13173        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13174        let text_layout_details = &self.text_layout_details(window);
13175        self.change_selections(Default::default(), window, cx, |s| {
13176            s.move_heads_with(|map, head, goal| {
13177                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
13178            })
13179        })
13180    }
13181
13182    pub fn select_page_up(
13183        &mut self,
13184        _: &SelectPageUp,
13185        window: &mut Window,
13186        cx: &mut Context<Self>,
13187    ) {
13188        let Some(row_count) = self.visible_row_count() else {
13189            return;
13190        };
13191
13192        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13193
13194        let text_layout_details = &self.text_layout_details(window);
13195
13196        self.change_selections(Default::default(), window, cx, |s| {
13197            s.move_heads_with(|map, head, goal| {
13198                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
13199            })
13200        })
13201    }
13202
13203    pub fn move_page_up(
13204        &mut self,
13205        action: &MovePageUp,
13206        window: &mut Window,
13207        cx: &mut Context<Self>,
13208    ) {
13209        if self.take_rename(true, window, cx).is_some() {
13210            return;
13211        }
13212
13213        if self
13214            .context_menu
13215            .borrow_mut()
13216            .as_mut()
13217            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
13218            .unwrap_or(false)
13219        {
13220            return;
13221        }
13222
13223        if matches!(self.mode, EditorMode::SingleLine) {
13224            cx.propagate();
13225            return;
13226        }
13227
13228        let Some(row_count) = self.visible_row_count() else {
13229            return;
13230        };
13231
13232        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13233
13234        let effects = if action.center_cursor {
13235            SelectionEffects::scroll(Autoscroll::center())
13236        } else {
13237            SelectionEffects::default()
13238        };
13239
13240        let text_layout_details = &self.text_layout_details(window);
13241
13242        self.change_selections(effects, window, cx, |s| {
13243            s.move_with(|map, selection| {
13244                if !selection.is_empty() {
13245                    selection.goal = SelectionGoal::None;
13246                }
13247                let (cursor, goal) = movement::up_by_rows(
13248                    map,
13249                    selection.end,
13250                    row_count,
13251                    selection.goal,
13252                    false,
13253                    text_layout_details,
13254                );
13255                selection.collapse_to(cursor, goal);
13256            });
13257        });
13258    }
13259
13260    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
13261        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13262        let text_layout_details = &self.text_layout_details(window);
13263        self.change_selections(Default::default(), window, cx, |s| {
13264            s.move_heads_with(|map, head, goal| {
13265                movement::up(map, head, goal, false, text_layout_details)
13266            })
13267        })
13268    }
13269
13270    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
13271        self.take_rename(true, window, cx);
13272
13273        if self.mode.is_single_line() {
13274            cx.propagate();
13275            return;
13276        }
13277
13278        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13279
13280        let text_layout_details = &self.text_layout_details(window);
13281        let selection_count = self.selections.count();
13282        let first_selection = self.selections.first_anchor();
13283
13284        self.change_selections(Default::default(), window, cx, |s| {
13285            s.move_with(|map, selection| {
13286                if !selection.is_empty() {
13287                    selection.goal = SelectionGoal::None;
13288                }
13289                let (cursor, goal) = movement::down(
13290                    map,
13291                    selection.end,
13292                    selection.goal,
13293                    false,
13294                    text_layout_details,
13295                );
13296                selection.collapse_to(cursor, goal);
13297            });
13298        });
13299
13300        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
13301        {
13302            cx.propagate();
13303        }
13304    }
13305
13306    pub fn select_page_down(
13307        &mut self,
13308        _: &SelectPageDown,
13309        window: &mut Window,
13310        cx: &mut Context<Self>,
13311    ) {
13312        let Some(row_count) = self.visible_row_count() else {
13313            return;
13314        };
13315
13316        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13317
13318        let text_layout_details = &self.text_layout_details(window);
13319
13320        self.change_selections(Default::default(), window, cx, |s| {
13321            s.move_heads_with(|map, head, goal| {
13322                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
13323            })
13324        })
13325    }
13326
13327    pub fn move_page_down(
13328        &mut self,
13329        action: &MovePageDown,
13330        window: &mut Window,
13331        cx: &mut Context<Self>,
13332    ) {
13333        if self.take_rename(true, window, cx).is_some() {
13334            return;
13335        }
13336
13337        if self
13338            .context_menu
13339            .borrow_mut()
13340            .as_mut()
13341            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
13342            .unwrap_or(false)
13343        {
13344            return;
13345        }
13346
13347        if matches!(self.mode, EditorMode::SingleLine) {
13348            cx.propagate();
13349            return;
13350        }
13351
13352        let Some(row_count) = self.visible_row_count() else {
13353            return;
13354        };
13355
13356        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13357
13358        let effects = if action.center_cursor {
13359            SelectionEffects::scroll(Autoscroll::center())
13360        } else {
13361            SelectionEffects::default()
13362        };
13363
13364        let text_layout_details = &self.text_layout_details(window);
13365        self.change_selections(effects, window, cx, |s| {
13366            s.move_with(|map, selection| {
13367                if !selection.is_empty() {
13368                    selection.goal = SelectionGoal::None;
13369                }
13370                let (cursor, goal) = movement::down_by_rows(
13371                    map,
13372                    selection.end,
13373                    row_count,
13374                    selection.goal,
13375                    false,
13376                    text_layout_details,
13377                );
13378                selection.collapse_to(cursor, goal);
13379            });
13380        });
13381    }
13382
13383    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
13384        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13385        let text_layout_details = &self.text_layout_details(window);
13386        self.change_selections(Default::default(), window, cx, |s| {
13387            s.move_heads_with(|map, head, goal| {
13388                movement::down(map, head, goal, false, text_layout_details)
13389            })
13390        });
13391    }
13392
13393    pub fn context_menu_first(
13394        &mut self,
13395        _: &ContextMenuFirst,
13396        window: &mut Window,
13397        cx: &mut Context<Self>,
13398    ) {
13399        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13400            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
13401        }
13402    }
13403
13404    pub fn context_menu_prev(
13405        &mut self,
13406        _: &ContextMenuPrevious,
13407        window: &mut Window,
13408        cx: &mut Context<Self>,
13409    ) {
13410        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13411            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
13412        }
13413    }
13414
13415    pub fn context_menu_next(
13416        &mut self,
13417        _: &ContextMenuNext,
13418        window: &mut Window,
13419        cx: &mut Context<Self>,
13420    ) {
13421        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13422            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
13423        }
13424    }
13425
13426    pub fn context_menu_last(
13427        &mut self,
13428        _: &ContextMenuLast,
13429        window: &mut Window,
13430        cx: &mut Context<Self>,
13431    ) {
13432        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13433            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
13434        }
13435    }
13436
13437    pub fn signature_help_prev(
13438        &mut self,
13439        _: &SignatureHelpPrevious,
13440        _: &mut Window,
13441        cx: &mut Context<Self>,
13442    ) {
13443        if let Some(popover) = self.signature_help_state.popover_mut() {
13444            if popover.current_signature == 0 {
13445                popover.current_signature = popover.signatures.len() - 1;
13446            } else {
13447                popover.current_signature -= 1;
13448            }
13449            cx.notify();
13450        }
13451    }
13452
13453    pub fn signature_help_next(
13454        &mut self,
13455        _: &SignatureHelpNext,
13456        _: &mut Window,
13457        cx: &mut Context<Self>,
13458    ) {
13459        if let Some(popover) = self.signature_help_state.popover_mut() {
13460            if popover.current_signature + 1 == popover.signatures.len() {
13461                popover.current_signature = 0;
13462            } else {
13463                popover.current_signature += 1;
13464            }
13465            cx.notify();
13466        }
13467    }
13468
13469    pub fn move_to_previous_word_start(
13470        &mut self,
13471        _: &MoveToPreviousWordStart,
13472        window: &mut Window,
13473        cx: &mut Context<Self>,
13474    ) {
13475        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13476        self.change_selections(Default::default(), window, cx, |s| {
13477            s.move_cursors_with(|map, head, _| {
13478                (
13479                    movement::previous_word_start(map, head),
13480                    SelectionGoal::None,
13481                )
13482            });
13483        })
13484    }
13485
13486    pub fn move_to_previous_subword_start(
13487        &mut self,
13488        _: &MoveToPreviousSubwordStart,
13489        window: &mut Window,
13490        cx: &mut Context<Self>,
13491    ) {
13492        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13493        self.change_selections(Default::default(), window, cx, |s| {
13494            s.move_cursors_with(|map, head, _| {
13495                (
13496                    movement::previous_subword_start(map, head),
13497                    SelectionGoal::None,
13498                )
13499            });
13500        })
13501    }
13502
13503    pub fn select_to_previous_word_start(
13504        &mut self,
13505        _: &SelectToPreviousWordStart,
13506        window: &mut Window,
13507        cx: &mut Context<Self>,
13508    ) {
13509        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13510        self.change_selections(Default::default(), window, cx, |s| {
13511            s.move_heads_with(|map, head, _| {
13512                (
13513                    movement::previous_word_start(map, head),
13514                    SelectionGoal::None,
13515                )
13516            });
13517        })
13518    }
13519
13520    pub fn select_to_previous_subword_start(
13521        &mut self,
13522        _: &SelectToPreviousSubwordStart,
13523        window: &mut Window,
13524        cx: &mut Context<Self>,
13525    ) {
13526        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13527        self.change_selections(Default::default(), window, cx, |s| {
13528            s.move_heads_with(|map, head, _| {
13529                (
13530                    movement::previous_subword_start(map, head),
13531                    SelectionGoal::None,
13532                )
13533            });
13534        })
13535    }
13536
13537    pub fn delete_to_previous_word_start(
13538        &mut self,
13539        action: &DeleteToPreviousWordStart,
13540        window: &mut Window,
13541        cx: &mut Context<Self>,
13542    ) {
13543        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13544        self.transact(window, cx, |this, window, cx| {
13545            this.select_autoclose_pair(window, cx);
13546            this.change_selections(Default::default(), window, cx, |s| {
13547                s.move_with(|map, selection| {
13548                    if selection.is_empty() {
13549                        let mut cursor = if action.ignore_newlines {
13550                            movement::previous_word_start(map, selection.head())
13551                        } else {
13552                            movement::previous_word_start_or_newline(map, selection.head())
13553                        };
13554                        cursor = movement::adjust_greedy_deletion(
13555                            map,
13556                            selection.head(),
13557                            cursor,
13558                            action.ignore_brackets,
13559                        );
13560                        selection.set_head(cursor, SelectionGoal::None);
13561                    }
13562                });
13563            });
13564            this.insert("", window, cx);
13565        });
13566    }
13567
13568    pub fn delete_to_previous_subword_start(
13569        &mut self,
13570        _: &DeleteToPreviousSubwordStart,
13571        window: &mut Window,
13572        cx: &mut Context<Self>,
13573    ) {
13574        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13575        self.transact(window, cx, |this, window, cx| {
13576            this.select_autoclose_pair(window, cx);
13577            this.change_selections(Default::default(), window, cx, |s| {
13578                s.move_with(|map, selection| {
13579                    if selection.is_empty() {
13580                        let mut cursor = movement::previous_subword_start(map, selection.head());
13581                        cursor =
13582                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13583                        selection.set_head(cursor, SelectionGoal::None);
13584                    }
13585                });
13586            });
13587            this.insert("", window, cx);
13588        });
13589    }
13590
13591    pub fn move_to_next_word_end(
13592        &mut self,
13593        _: &MoveToNextWordEnd,
13594        window: &mut Window,
13595        cx: &mut Context<Self>,
13596    ) {
13597        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13598        self.change_selections(Default::default(), window, cx, |s| {
13599            s.move_cursors_with(|map, head, _| {
13600                (movement::next_word_end(map, head), SelectionGoal::None)
13601            });
13602        })
13603    }
13604
13605    pub fn move_to_next_subword_end(
13606        &mut self,
13607        _: &MoveToNextSubwordEnd,
13608        window: &mut Window,
13609        cx: &mut Context<Self>,
13610    ) {
13611        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13612        self.change_selections(Default::default(), window, cx, |s| {
13613            s.move_cursors_with(|map, head, _| {
13614                (movement::next_subword_end(map, head), SelectionGoal::None)
13615            });
13616        })
13617    }
13618
13619    pub fn select_to_next_word_end(
13620        &mut self,
13621        _: &SelectToNextWordEnd,
13622        window: &mut Window,
13623        cx: &mut Context<Self>,
13624    ) {
13625        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13626        self.change_selections(Default::default(), window, cx, |s| {
13627            s.move_heads_with(|map, head, _| {
13628                (movement::next_word_end(map, head), SelectionGoal::None)
13629            });
13630        })
13631    }
13632
13633    pub fn select_to_next_subword_end(
13634        &mut self,
13635        _: &SelectToNextSubwordEnd,
13636        window: &mut Window,
13637        cx: &mut Context<Self>,
13638    ) {
13639        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13640        self.change_selections(Default::default(), window, cx, |s| {
13641            s.move_heads_with(|map, head, _| {
13642                (movement::next_subword_end(map, head), SelectionGoal::None)
13643            });
13644        })
13645    }
13646
13647    pub fn delete_to_next_word_end(
13648        &mut self,
13649        action: &DeleteToNextWordEnd,
13650        window: &mut Window,
13651        cx: &mut Context<Self>,
13652    ) {
13653        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13654        self.transact(window, cx, |this, window, cx| {
13655            this.change_selections(Default::default(), window, cx, |s| {
13656                s.move_with(|map, selection| {
13657                    if selection.is_empty() {
13658                        let mut cursor = if action.ignore_newlines {
13659                            movement::next_word_end(map, selection.head())
13660                        } else {
13661                            movement::next_word_end_or_newline(map, selection.head())
13662                        };
13663                        cursor = movement::adjust_greedy_deletion(
13664                            map,
13665                            selection.head(),
13666                            cursor,
13667                            action.ignore_brackets,
13668                        );
13669                        selection.set_head(cursor, SelectionGoal::None);
13670                    }
13671                });
13672            });
13673            this.insert("", window, cx);
13674        });
13675    }
13676
13677    pub fn delete_to_next_subword_end(
13678        &mut self,
13679        _: &DeleteToNextSubwordEnd,
13680        window: &mut Window,
13681        cx: &mut Context<Self>,
13682    ) {
13683        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13684        self.transact(window, cx, |this, window, cx| {
13685            this.change_selections(Default::default(), window, cx, |s| {
13686                s.move_with(|map, selection| {
13687                    if selection.is_empty() {
13688                        let mut cursor = movement::next_subword_end(map, selection.head());
13689                        cursor =
13690                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13691                        selection.set_head(cursor, SelectionGoal::None);
13692                    }
13693                });
13694            });
13695            this.insert("", window, cx);
13696        });
13697    }
13698
13699    pub fn move_to_beginning_of_line(
13700        &mut self,
13701        action: &MoveToBeginningOfLine,
13702        window: &mut Window,
13703        cx: &mut Context<Self>,
13704    ) {
13705        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13706        self.change_selections(Default::default(), window, cx, |s| {
13707            s.move_cursors_with(|map, head, _| {
13708                (
13709                    movement::indented_line_beginning(
13710                        map,
13711                        head,
13712                        action.stop_at_soft_wraps,
13713                        action.stop_at_indent,
13714                    ),
13715                    SelectionGoal::None,
13716                )
13717            });
13718        })
13719    }
13720
13721    pub fn select_to_beginning_of_line(
13722        &mut self,
13723        action: &SelectToBeginningOfLine,
13724        window: &mut Window,
13725        cx: &mut Context<Self>,
13726    ) {
13727        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13728        self.change_selections(Default::default(), window, cx, |s| {
13729            s.move_heads_with(|map, head, _| {
13730                (
13731                    movement::indented_line_beginning(
13732                        map,
13733                        head,
13734                        action.stop_at_soft_wraps,
13735                        action.stop_at_indent,
13736                    ),
13737                    SelectionGoal::None,
13738                )
13739            });
13740        });
13741    }
13742
13743    pub fn delete_to_beginning_of_line(
13744        &mut self,
13745        action: &DeleteToBeginningOfLine,
13746        window: &mut Window,
13747        cx: &mut Context<Self>,
13748    ) {
13749        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13750        self.transact(window, cx, |this, window, cx| {
13751            this.change_selections(Default::default(), window, cx, |s| {
13752                s.move_with(|_, selection| {
13753                    selection.reversed = true;
13754                });
13755            });
13756
13757            this.select_to_beginning_of_line(
13758                &SelectToBeginningOfLine {
13759                    stop_at_soft_wraps: false,
13760                    stop_at_indent: action.stop_at_indent,
13761                },
13762                window,
13763                cx,
13764            );
13765            this.backspace(&Backspace, window, cx);
13766        });
13767    }
13768
13769    pub fn move_to_end_of_line(
13770        &mut self,
13771        action: &MoveToEndOfLine,
13772        window: &mut Window,
13773        cx: &mut Context<Self>,
13774    ) {
13775        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13776        self.change_selections(Default::default(), window, cx, |s| {
13777            s.move_cursors_with(|map, head, _| {
13778                (
13779                    movement::line_end(map, head, action.stop_at_soft_wraps),
13780                    SelectionGoal::None,
13781                )
13782            });
13783        })
13784    }
13785
13786    pub fn select_to_end_of_line(
13787        &mut self,
13788        action: &SelectToEndOfLine,
13789        window: &mut Window,
13790        cx: &mut Context<Self>,
13791    ) {
13792        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13793        self.change_selections(Default::default(), window, cx, |s| {
13794            s.move_heads_with(|map, head, _| {
13795                (
13796                    movement::line_end(map, head, action.stop_at_soft_wraps),
13797                    SelectionGoal::None,
13798                )
13799            });
13800        })
13801    }
13802
13803    pub fn delete_to_end_of_line(
13804        &mut self,
13805        _: &DeleteToEndOfLine,
13806        window: &mut Window,
13807        cx: &mut Context<Self>,
13808    ) {
13809        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13810        self.transact(window, cx, |this, window, cx| {
13811            this.select_to_end_of_line(
13812                &SelectToEndOfLine {
13813                    stop_at_soft_wraps: false,
13814                },
13815                window,
13816                cx,
13817            );
13818            this.delete(&Delete, window, cx);
13819        });
13820    }
13821
13822    pub fn cut_to_end_of_line(
13823        &mut self,
13824        action: &CutToEndOfLine,
13825        window: &mut Window,
13826        cx: &mut Context<Self>,
13827    ) {
13828        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13829        self.transact(window, cx, |this, window, cx| {
13830            this.select_to_end_of_line(
13831                &SelectToEndOfLine {
13832                    stop_at_soft_wraps: false,
13833                },
13834                window,
13835                cx,
13836            );
13837            if !action.stop_at_newlines {
13838                this.change_selections(Default::default(), window, cx, |s| {
13839                    s.move_with(|_, sel| {
13840                        if sel.is_empty() {
13841                            sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
13842                        }
13843                    });
13844                });
13845            }
13846            this.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13847            let item = this.cut_common(false, window, cx);
13848            cx.write_to_clipboard(item);
13849        });
13850    }
13851
13852    pub fn move_to_start_of_paragraph(
13853        &mut self,
13854        _: &MoveToStartOfParagraph,
13855        window: &mut Window,
13856        cx: &mut Context<Self>,
13857    ) {
13858        if matches!(self.mode, EditorMode::SingleLine) {
13859            cx.propagate();
13860            return;
13861        }
13862        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13863        self.change_selections(Default::default(), window, cx, |s| {
13864            s.move_with(|map, selection| {
13865                selection.collapse_to(
13866                    movement::start_of_paragraph(map, selection.head(), 1),
13867                    SelectionGoal::None,
13868                )
13869            });
13870        })
13871    }
13872
13873    pub fn move_to_end_of_paragraph(
13874        &mut self,
13875        _: &MoveToEndOfParagraph,
13876        window: &mut Window,
13877        cx: &mut Context<Self>,
13878    ) {
13879        if matches!(self.mode, EditorMode::SingleLine) {
13880            cx.propagate();
13881            return;
13882        }
13883        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13884        self.change_selections(Default::default(), window, cx, |s| {
13885            s.move_with(|map, selection| {
13886                selection.collapse_to(
13887                    movement::end_of_paragraph(map, selection.head(), 1),
13888                    SelectionGoal::None,
13889                )
13890            });
13891        })
13892    }
13893
13894    pub fn select_to_start_of_paragraph(
13895        &mut self,
13896        _: &SelectToStartOfParagraph,
13897        window: &mut Window,
13898        cx: &mut Context<Self>,
13899    ) {
13900        if matches!(self.mode, EditorMode::SingleLine) {
13901            cx.propagate();
13902            return;
13903        }
13904        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13905        self.change_selections(Default::default(), window, cx, |s| {
13906            s.move_heads_with(|map, head, _| {
13907                (
13908                    movement::start_of_paragraph(map, head, 1),
13909                    SelectionGoal::None,
13910                )
13911            });
13912        })
13913    }
13914
13915    pub fn select_to_end_of_paragraph(
13916        &mut self,
13917        _: &SelectToEndOfParagraph,
13918        window: &mut Window,
13919        cx: &mut Context<Self>,
13920    ) {
13921        if matches!(self.mode, EditorMode::SingleLine) {
13922            cx.propagate();
13923            return;
13924        }
13925        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13926        self.change_selections(Default::default(), window, cx, |s| {
13927            s.move_heads_with(|map, head, _| {
13928                (
13929                    movement::end_of_paragraph(map, head, 1),
13930                    SelectionGoal::None,
13931                )
13932            });
13933        })
13934    }
13935
13936    pub fn move_to_start_of_excerpt(
13937        &mut self,
13938        _: &MoveToStartOfExcerpt,
13939        window: &mut Window,
13940        cx: &mut Context<Self>,
13941    ) {
13942        if matches!(self.mode, EditorMode::SingleLine) {
13943            cx.propagate();
13944            return;
13945        }
13946        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13947        self.change_selections(Default::default(), window, cx, |s| {
13948            s.move_with(|map, selection| {
13949                selection.collapse_to(
13950                    movement::start_of_excerpt(
13951                        map,
13952                        selection.head(),
13953                        workspace::searchable::Direction::Prev,
13954                    ),
13955                    SelectionGoal::None,
13956                )
13957            });
13958        })
13959    }
13960
13961    pub fn move_to_start_of_next_excerpt(
13962        &mut self,
13963        _: &MoveToStartOfNextExcerpt,
13964        window: &mut Window,
13965        cx: &mut Context<Self>,
13966    ) {
13967        if matches!(self.mode, EditorMode::SingleLine) {
13968            cx.propagate();
13969            return;
13970        }
13971
13972        self.change_selections(Default::default(), window, cx, |s| {
13973            s.move_with(|map, selection| {
13974                selection.collapse_to(
13975                    movement::start_of_excerpt(
13976                        map,
13977                        selection.head(),
13978                        workspace::searchable::Direction::Next,
13979                    ),
13980                    SelectionGoal::None,
13981                )
13982            });
13983        })
13984    }
13985
13986    pub fn move_to_end_of_excerpt(
13987        &mut self,
13988        _: &MoveToEndOfExcerpt,
13989        window: &mut Window,
13990        cx: &mut Context<Self>,
13991    ) {
13992        if matches!(self.mode, EditorMode::SingleLine) {
13993            cx.propagate();
13994            return;
13995        }
13996        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13997        self.change_selections(Default::default(), window, cx, |s| {
13998            s.move_with(|map, selection| {
13999                selection.collapse_to(
14000                    movement::end_of_excerpt(
14001                        map,
14002                        selection.head(),
14003                        workspace::searchable::Direction::Next,
14004                    ),
14005                    SelectionGoal::None,
14006                )
14007            });
14008        })
14009    }
14010
14011    pub fn move_to_end_of_previous_excerpt(
14012        &mut self,
14013        _: &MoveToEndOfPreviousExcerpt,
14014        window: &mut Window,
14015        cx: &mut Context<Self>,
14016    ) {
14017        if matches!(self.mode, EditorMode::SingleLine) {
14018            cx.propagate();
14019            return;
14020        }
14021        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14022        self.change_selections(Default::default(), window, cx, |s| {
14023            s.move_with(|map, selection| {
14024                selection.collapse_to(
14025                    movement::end_of_excerpt(
14026                        map,
14027                        selection.head(),
14028                        workspace::searchable::Direction::Prev,
14029                    ),
14030                    SelectionGoal::None,
14031                )
14032            });
14033        })
14034    }
14035
14036    pub fn select_to_start_of_excerpt(
14037        &mut self,
14038        _: &SelectToStartOfExcerpt,
14039        window: &mut Window,
14040        cx: &mut Context<Self>,
14041    ) {
14042        if matches!(self.mode, EditorMode::SingleLine) {
14043            cx.propagate();
14044            return;
14045        }
14046        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14047        self.change_selections(Default::default(), window, cx, |s| {
14048            s.move_heads_with(|map, head, _| {
14049                (
14050                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
14051                    SelectionGoal::None,
14052                )
14053            });
14054        })
14055    }
14056
14057    pub fn select_to_start_of_next_excerpt(
14058        &mut self,
14059        _: &SelectToStartOfNextExcerpt,
14060        window: &mut Window,
14061        cx: &mut Context<Self>,
14062    ) {
14063        if matches!(self.mode, EditorMode::SingleLine) {
14064            cx.propagate();
14065            return;
14066        }
14067        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14068        self.change_selections(Default::default(), window, cx, |s| {
14069            s.move_heads_with(|map, head, _| {
14070                (
14071                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
14072                    SelectionGoal::None,
14073                )
14074            });
14075        })
14076    }
14077
14078    pub fn select_to_end_of_excerpt(
14079        &mut self,
14080        _: &SelectToEndOfExcerpt,
14081        window: &mut Window,
14082        cx: &mut Context<Self>,
14083    ) {
14084        if matches!(self.mode, EditorMode::SingleLine) {
14085            cx.propagate();
14086            return;
14087        }
14088        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14089        self.change_selections(Default::default(), window, cx, |s| {
14090            s.move_heads_with(|map, head, _| {
14091                (
14092                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
14093                    SelectionGoal::None,
14094                )
14095            });
14096        })
14097    }
14098
14099    pub fn select_to_end_of_previous_excerpt(
14100        &mut self,
14101        _: &SelectToEndOfPreviousExcerpt,
14102        window: &mut Window,
14103        cx: &mut Context<Self>,
14104    ) {
14105        if matches!(self.mode, EditorMode::SingleLine) {
14106            cx.propagate();
14107            return;
14108        }
14109        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14110        self.change_selections(Default::default(), window, cx, |s| {
14111            s.move_heads_with(|map, head, _| {
14112                (
14113                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
14114                    SelectionGoal::None,
14115                )
14116            });
14117        })
14118    }
14119
14120    pub fn move_to_beginning(
14121        &mut self,
14122        _: &MoveToBeginning,
14123        window: &mut Window,
14124        cx: &mut Context<Self>,
14125    ) {
14126        if matches!(self.mode, EditorMode::SingleLine) {
14127            cx.propagate();
14128            return;
14129        }
14130        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14131        self.change_selections(Default::default(), window, cx, |s| {
14132            s.select_ranges(vec![0..0]);
14133        });
14134    }
14135
14136    pub fn select_to_beginning(
14137        &mut self,
14138        _: &SelectToBeginning,
14139        window: &mut Window,
14140        cx: &mut Context<Self>,
14141    ) {
14142        let mut selection = self.selections.last::<Point>(&self.display_snapshot(cx));
14143        selection.set_head(Point::zero(), SelectionGoal::None);
14144        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14145        self.change_selections(Default::default(), window, cx, |s| {
14146            s.select(vec![selection]);
14147        });
14148    }
14149
14150    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
14151        if matches!(self.mode, EditorMode::SingleLine) {
14152            cx.propagate();
14153            return;
14154        }
14155        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14156        let cursor = self.buffer.read(cx).read(cx).len();
14157        self.change_selections(Default::default(), window, cx, |s| {
14158            s.select_ranges(vec![cursor..cursor])
14159        });
14160    }
14161
14162    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
14163        self.nav_history = nav_history;
14164    }
14165
14166    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
14167        self.nav_history.as_ref()
14168    }
14169
14170    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
14171        self.push_to_nav_history(
14172            self.selections.newest_anchor().head(),
14173            None,
14174            false,
14175            true,
14176            cx,
14177        );
14178    }
14179
14180    fn push_to_nav_history(
14181        &mut self,
14182        cursor_anchor: Anchor,
14183        new_position: Option<Point>,
14184        is_deactivate: bool,
14185        always: bool,
14186        cx: &mut Context<Self>,
14187    ) {
14188        if let Some(nav_history) = self.nav_history.as_mut() {
14189            let buffer = self.buffer.read(cx).read(cx);
14190            let cursor_position = cursor_anchor.to_point(&buffer);
14191            let scroll_state = self.scroll_manager.anchor();
14192            let scroll_top_row = scroll_state.top_row(&buffer);
14193            drop(buffer);
14194
14195            if let Some(new_position) = new_position {
14196                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
14197                if row_delta == 0 || (row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA && !always) {
14198                    return;
14199                }
14200            }
14201
14202            nav_history.push(
14203                Some(NavigationData {
14204                    cursor_anchor,
14205                    cursor_position,
14206                    scroll_anchor: scroll_state,
14207                    scroll_top_row,
14208                }),
14209                cx,
14210            );
14211            cx.emit(EditorEvent::PushedToNavHistory {
14212                anchor: cursor_anchor,
14213                is_deactivate,
14214            })
14215        }
14216    }
14217
14218    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
14219        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14220        let buffer = self.buffer.read(cx).snapshot(cx);
14221        let mut selection = self.selections.first::<usize>(&self.display_snapshot(cx));
14222        selection.set_head(buffer.len(), SelectionGoal::None);
14223        self.change_selections(Default::default(), window, cx, |s| {
14224            s.select(vec![selection]);
14225        });
14226    }
14227
14228    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
14229        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14230        let end = self.buffer.read(cx).read(cx).len();
14231        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14232            s.select_ranges(vec![0..end]);
14233        });
14234    }
14235
14236    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
14237        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14238        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14239        let mut selections = self.selections.all::<Point>(&display_map);
14240        let max_point = display_map.buffer_snapshot().max_point();
14241        for selection in &mut selections {
14242            let rows = selection.spanned_rows(true, &display_map);
14243            selection.start = Point::new(rows.start.0, 0);
14244            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
14245            selection.reversed = false;
14246        }
14247        self.change_selections(Default::default(), window, cx, |s| {
14248            s.select(selections);
14249        });
14250    }
14251
14252    pub fn split_selection_into_lines(
14253        &mut self,
14254        action: &SplitSelectionIntoLines,
14255        window: &mut Window,
14256        cx: &mut Context<Self>,
14257    ) {
14258        let selections = self
14259            .selections
14260            .all::<Point>(&self.display_snapshot(cx))
14261            .into_iter()
14262            .map(|selection| selection.start..selection.end)
14263            .collect::<Vec<_>>();
14264        self.unfold_ranges(&selections, true, true, cx);
14265
14266        let mut new_selection_ranges = Vec::new();
14267        {
14268            let buffer = self.buffer.read(cx).read(cx);
14269            for selection in selections {
14270                for row in selection.start.row..selection.end.row {
14271                    let line_start = Point::new(row, 0);
14272                    let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
14273
14274                    if action.keep_selections {
14275                        // Keep the selection range for each line
14276                        let selection_start = if row == selection.start.row {
14277                            selection.start
14278                        } else {
14279                            line_start
14280                        };
14281                        new_selection_ranges.push(selection_start..line_end);
14282                    } else {
14283                        // Collapse to cursor at end of line
14284                        new_selection_ranges.push(line_end..line_end);
14285                    }
14286                }
14287
14288                let is_multiline_selection = selection.start.row != selection.end.row;
14289                // Don't insert last one if it's a multi-line selection ending at the start of a line,
14290                // so this action feels more ergonomic when paired with other selection operations
14291                let should_skip_last = is_multiline_selection && selection.end.column == 0;
14292                if !should_skip_last {
14293                    if action.keep_selections {
14294                        if is_multiline_selection {
14295                            let line_start = Point::new(selection.end.row, 0);
14296                            new_selection_ranges.push(line_start..selection.end);
14297                        } else {
14298                            new_selection_ranges.push(selection.start..selection.end);
14299                        }
14300                    } else {
14301                        new_selection_ranges.push(selection.end..selection.end);
14302                    }
14303                }
14304            }
14305        }
14306        self.change_selections(Default::default(), window, cx, |s| {
14307            s.select_ranges(new_selection_ranges);
14308        });
14309    }
14310
14311    pub fn add_selection_above(
14312        &mut self,
14313        action: &AddSelectionAbove,
14314        window: &mut Window,
14315        cx: &mut Context<Self>,
14316    ) {
14317        self.add_selection(true, action.skip_soft_wrap, window, cx);
14318    }
14319
14320    pub fn add_selection_below(
14321        &mut self,
14322        action: &AddSelectionBelow,
14323        window: &mut Window,
14324        cx: &mut Context<Self>,
14325    ) {
14326        self.add_selection(false, action.skip_soft_wrap, window, cx);
14327    }
14328
14329    fn add_selection(
14330        &mut self,
14331        above: bool,
14332        skip_soft_wrap: bool,
14333        window: &mut Window,
14334        cx: &mut Context<Self>,
14335    ) {
14336        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14337
14338        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14339        let all_selections = self.selections.all::<Point>(&display_map);
14340        let text_layout_details = self.text_layout_details(window);
14341
14342        let (mut columnar_selections, new_selections_to_columnarize) = {
14343            if let Some(state) = self.add_selections_state.as_ref() {
14344                let columnar_selection_ids: HashSet<_> = state
14345                    .groups
14346                    .iter()
14347                    .flat_map(|group| group.stack.iter())
14348                    .copied()
14349                    .collect();
14350
14351                all_selections
14352                    .into_iter()
14353                    .partition(|s| columnar_selection_ids.contains(&s.id))
14354            } else {
14355                (Vec::new(), all_selections)
14356            }
14357        };
14358
14359        let mut state = self
14360            .add_selections_state
14361            .take()
14362            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
14363
14364        for selection in new_selections_to_columnarize {
14365            let range = selection.display_range(&display_map).sorted();
14366            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
14367            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
14368            let positions = start_x.min(end_x)..start_x.max(end_x);
14369            let mut stack = Vec::new();
14370            for row in range.start.row().0..=range.end.row().0 {
14371                if let Some(selection) = self.selections.build_columnar_selection(
14372                    &display_map,
14373                    DisplayRow(row),
14374                    &positions,
14375                    selection.reversed,
14376                    &text_layout_details,
14377                ) {
14378                    stack.push(selection.id);
14379                    columnar_selections.push(selection);
14380                }
14381            }
14382            if !stack.is_empty() {
14383                if above {
14384                    stack.reverse();
14385                }
14386                state.groups.push(AddSelectionsGroup { above, stack });
14387            }
14388        }
14389
14390        let mut final_selections = Vec::new();
14391        let end_row = if above {
14392            DisplayRow(0)
14393        } else {
14394            display_map.max_point().row()
14395        };
14396
14397        let mut last_added_item_per_group = HashMap::default();
14398        for group in state.groups.iter_mut() {
14399            if let Some(last_id) = group.stack.last() {
14400                last_added_item_per_group.insert(*last_id, group);
14401            }
14402        }
14403
14404        for selection in columnar_selections {
14405            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
14406                if above == group.above {
14407                    let range = selection.display_range(&display_map).sorted();
14408                    debug_assert_eq!(range.start.row(), range.end.row());
14409                    let mut row = range.start.row();
14410                    let positions =
14411                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
14412                            Pixels::from(start)..Pixels::from(end)
14413                        } else {
14414                            let start_x =
14415                                display_map.x_for_display_point(range.start, &text_layout_details);
14416                            let end_x =
14417                                display_map.x_for_display_point(range.end, &text_layout_details);
14418                            start_x.min(end_x)..start_x.max(end_x)
14419                        };
14420
14421                    let mut maybe_new_selection = None;
14422                    let direction = if above { -1 } else { 1 };
14423
14424                    while row != end_row {
14425                        if skip_soft_wrap {
14426                            row = display_map
14427                                .start_of_relative_buffer_row(DisplayPoint::new(row, 0), direction)
14428                                .row();
14429                        } else if above {
14430                            row.0 -= 1;
14431                        } else {
14432                            row.0 += 1;
14433                        }
14434
14435                        if let Some(new_selection) = self.selections.build_columnar_selection(
14436                            &display_map,
14437                            row,
14438                            &positions,
14439                            selection.reversed,
14440                            &text_layout_details,
14441                        ) {
14442                            maybe_new_selection = Some(new_selection);
14443                            break;
14444                        }
14445                    }
14446
14447                    if let Some(new_selection) = maybe_new_selection {
14448                        group.stack.push(new_selection.id);
14449                        if above {
14450                            final_selections.push(new_selection);
14451                            final_selections.push(selection);
14452                        } else {
14453                            final_selections.push(selection);
14454                            final_selections.push(new_selection);
14455                        }
14456                    } else {
14457                        final_selections.push(selection);
14458                    }
14459                } else {
14460                    group.stack.pop();
14461                }
14462            } else {
14463                final_selections.push(selection);
14464            }
14465        }
14466
14467        self.change_selections(Default::default(), window, cx, |s| {
14468            s.select(final_selections);
14469        });
14470
14471        let final_selection_ids: HashSet<_> = self
14472            .selections
14473            .all::<Point>(&display_map)
14474            .iter()
14475            .map(|s| s.id)
14476            .collect();
14477        state.groups.retain_mut(|group| {
14478            // selections might get merged above so we remove invalid items from stacks
14479            group.stack.retain(|id| final_selection_ids.contains(id));
14480
14481            // single selection in stack can be treated as initial state
14482            group.stack.len() > 1
14483        });
14484
14485        if !state.groups.is_empty() {
14486            self.add_selections_state = Some(state);
14487        }
14488    }
14489
14490    fn select_match_ranges(
14491        &mut self,
14492        range: Range<usize>,
14493        reversed: bool,
14494        replace_newest: bool,
14495        auto_scroll: Option<Autoscroll>,
14496        window: &mut Window,
14497        cx: &mut Context<Editor>,
14498    ) {
14499        self.unfold_ranges(
14500            std::slice::from_ref(&range),
14501            false,
14502            auto_scroll.is_some(),
14503            cx,
14504        );
14505        let effects = if let Some(scroll) = auto_scroll {
14506            SelectionEffects::scroll(scroll)
14507        } else {
14508            SelectionEffects::no_scroll()
14509        };
14510        self.change_selections(effects, window, cx, |s| {
14511            if replace_newest {
14512                s.delete(s.newest_anchor().id);
14513            }
14514            if reversed {
14515                s.insert_range(range.end..range.start);
14516            } else {
14517                s.insert_range(range);
14518            }
14519        });
14520    }
14521
14522    pub fn select_next_match_internal(
14523        &mut self,
14524        display_map: &DisplaySnapshot,
14525        replace_newest: bool,
14526        autoscroll: Option<Autoscroll>,
14527        window: &mut Window,
14528        cx: &mut Context<Self>,
14529    ) -> Result<()> {
14530        let buffer = display_map.buffer_snapshot();
14531        let mut selections = self.selections.all::<usize>(&display_map);
14532        if let Some(mut select_next_state) = self.select_next_state.take() {
14533            let query = &select_next_state.query;
14534            if !select_next_state.done {
14535                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14536                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14537                let mut next_selected_range = None;
14538
14539                let bytes_after_last_selection =
14540                    buffer.bytes_in_range(last_selection.end..buffer.len());
14541                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
14542                let query_matches = query
14543                    .stream_find_iter(bytes_after_last_selection)
14544                    .map(|result| (last_selection.end, result))
14545                    .chain(
14546                        query
14547                            .stream_find_iter(bytes_before_first_selection)
14548                            .map(|result| (0, result)),
14549                    );
14550
14551                for (start_offset, query_match) in query_matches {
14552                    let query_match = query_match.unwrap(); // can only fail due to I/O
14553                    let offset_range =
14554                        start_offset + query_match.start()..start_offset + query_match.end();
14555
14556                    if !select_next_state.wordwise
14557                        || (!buffer.is_inside_word(offset_range.start, None)
14558                            && !buffer.is_inside_word(offset_range.end, None))
14559                    {
14560                        let idx = selections
14561                            .partition_point(|selection| selection.end <= offset_range.start);
14562                        let overlaps = selections
14563                            .get(idx)
14564                            .map_or(false, |selection| selection.start < offset_range.end);
14565
14566                        if !overlaps {
14567                            next_selected_range = Some(offset_range);
14568                            break;
14569                        }
14570                    }
14571                }
14572
14573                if let Some(next_selected_range) = next_selected_range {
14574                    self.select_match_ranges(
14575                        next_selected_range,
14576                        last_selection.reversed,
14577                        replace_newest,
14578                        autoscroll,
14579                        window,
14580                        cx,
14581                    );
14582                } else {
14583                    select_next_state.done = true;
14584                }
14585            }
14586
14587            self.select_next_state = Some(select_next_state);
14588        } else {
14589            let mut only_carets = true;
14590            let mut same_text_selected = true;
14591            let mut selected_text = None;
14592
14593            let mut selections_iter = selections.iter().peekable();
14594            while let Some(selection) = selections_iter.next() {
14595                if selection.start != selection.end {
14596                    only_carets = false;
14597                }
14598
14599                if same_text_selected {
14600                    if selected_text.is_none() {
14601                        selected_text =
14602                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14603                    }
14604
14605                    if let Some(next_selection) = selections_iter.peek() {
14606                        if next_selection.range().len() == selection.range().len() {
14607                            let next_selected_text = buffer
14608                                .text_for_range(next_selection.range())
14609                                .collect::<String>();
14610                            if Some(next_selected_text) != selected_text {
14611                                same_text_selected = false;
14612                                selected_text = None;
14613                            }
14614                        } else {
14615                            same_text_selected = false;
14616                            selected_text = None;
14617                        }
14618                    }
14619                }
14620            }
14621
14622            if only_carets {
14623                for selection in &mut selections {
14624                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
14625                    selection.start = word_range.start;
14626                    selection.end = word_range.end;
14627                    selection.goal = SelectionGoal::None;
14628                    selection.reversed = false;
14629                    self.select_match_ranges(
14630                        selection.start..selection.end,
14631                        selection.reversed,
14632                        replace_newest,
14633                        autoscroll,
14634                        window,
14635                        cx,
14636                    );
14637                }
14638
14639                if selections.len() == 1 {
14640                    let selection = selections
14641                        .last()
14642                        .expect("ensured that there's only one selection");
14643                    let query = buffer
14644                        .text_for_range(selection.start..selection.end)
14645                        .collect::<String>();
14646                    let is_empty = query.is_empty();
14647                    let select_state = SelectNextState {
14648                        query: AhoCorasick::new(&[query])?,
14649                        wordwise: true,
14650                        done: is_empty,
14651                    };
14652                    self.select_next_state = Some(select_state);
14653                } else {
14654                    self.select_next_state = None;
14655                }
14656            } else if let Some(selected_text) = selected_text {
14657                self.select_next_state = Some(SelectNextState {
14658                    query: AhoCorasick::new(&[selected_text])?,
14659                    wordwise: false,
14660                    done: false,
14661                });
14662                self.select_next_match_internal(
14663                    display_map,
14664                    replace_newest,
14665                    autoscroll,
14666                    window,
14667                    cx,
14668                )?;
14669            }
14670        }
14671        Ok(())
14672    }
14673
14674    pub fn select_all_matches(
14675        &mut self,
14676        _action: &SelectAllMatches,
14677        window: &mut Window,
14678        cx: &mut Context<Self>,
14679    ) -> Result<()> {
14680        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14681
14682        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14683
14684        self.select_next_match_internal(&display_map, false, None, window, cx)?;
14685        let Some(select_next_state) = self.select_next_state.as_mut() else {
14686            return Ok(());
14687        };
14688        if select_next_state.done {
14689            return Ok(());
14690        }
14691
14692        let mut new_selections = Vec::new();
14693
14694        let reversed = self.selections.oldest::<usize>(&display_map).reversed;
14695        let buffer = display_map.buffer_snapshot();
14696        let query_matches = select_next_state
14697            .query
14698            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
14699
14700        for query_match in query_matches.into_iter() {
14701            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
14702            let offset_range = if reversed {
14703                query_match.end()..query_match.start()
14704            } else {
14705                query_match.start()..query_match.end()
14706            };
14707
14708            if !select_next_state.wordwise
14709                || (!buffer.is_inside_word(offset_range.start, None)
14710                    && !buffer.is_inside_word(offset_range.end, None))
14711            {
14712                new_selections.push(offset_range.start..offset_range.end);
14713            }
14714        }
14715
14716        select_next_state.done = true;
14717
14718        if new_selections.is_empty() {
14719            log::error!("bug: new_selections is empty in select_all_matches");
14720            return Ok(());
14721        }
14722
14723        self.unfold_ranges(&new_selections.clone(), false, false, cx);
14724        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
14725            selections.select_ranges(new_selections)
14726        });
14727
14728        Ok(())
14729    }
14730
14731    pub fn select_next(
14732        &mut self,
14733        action: &SelectNext,
14734        window: &mut Window,
14735        cx: &mut Context<Self>,
14736    ) -> Result<()> {
14737        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14738        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14739        self.select_next_match_internal(
14740            &display_map,
14741            action.replace_newest,
14742            Some(Autoscroll::newest()),
14743            window,
14744            cx,
14745        )?;
14746        Ok(())
14747    }
14748
14749    pub fn select_previous(
14750        &mut self,
14751        action: &SelectPrevious,
14752        window: &mut Window,
14753        cx: &mut Context<Self>,
14754    ) -> Result<()> {
14755        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14756        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14757        let buffer = display_map.buffer_snapshot();
14758        let mut selections = self.selections.all::<usize>(&display_map);
14759        if let Some(mut select_prev_state) = self.select_prev_state.take() {
14760            let query = &select_prev_state.query;
14761            if !select_prev_state.done {
14762                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14763                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14764                let mut next_selected_range = None;
14765                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
14766                let bytes_before_last_selection =
14767                    buffer.reversed_bytes_in_range(0..last_selection.start);
14768                let bytes_after_first_selection =
14769                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
14770                let query_matches = query
14771                    .stream_find_iter(bytes_before_last_selection)
14772                    .map(|result| (last_selection.start, result))
14773                    .chain(
14774                        query
14775                            .stream_find_iter(bytes_after_first_selection)
14776                            .map(|result| (buffer.len(), result)),
14777                    );
14778                for (end_offset, query_match) in query_matches {
14779                    let query_match = query_match.unwrap(); // can only fail due to I/O
14780                    let offset_range =
14781                        end_offset - query_match.end()..end_offset - query_match.start();
14782
14783                    if !select_prev_state.wordwise
14784                        || (!buffer.is_inside_word(offset_range.start, None)
14785                            && !buffer.is_inside_word(offset_range.end, None))
14786                    {
14787                        next_selected_range = Some(offset_range);
14788                        break;
14789                    }
14790                }
14791
14792                if let Some(next_selected_range) = next_selected_range {
14793                    self.select_match_ranges(
14794                        next_selected_range,
14795                        last_selection.reversed,
14796                        action.replace_newest,
14797                        Some(Autoscroll::newest()),
14798                        window,
14799                        cx,
14800                    );
14801                } else {
14802                    select_prev_state.done = true;
14803                }
14804            }
14805
14806            self.select_prev_state = Some(select_prev_state);
14807        } else {
14808            let mut only_carets = true;
14809            let mut same_text_selected = true;
14810            let mut selected_text = None;
14811
14812            let mut selections_iter = selections.iter().peekable();
14813            while let Some(selection) = selections_iter.next() {
14814                if selection.start != selection.end {
14815                    only_carets = false;
14816                }
14817
14818                if same_text_selected {
14819                    if selected_text.is_none() {
14820                        selected_text =
14821                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14822                    }
14823
14824                    if let Some(next_selection) = selections_iter.peek() {
14825                        if next_selection.range().len() == selection.range().len() {
14826                            let next_selected_text = buffer
14827                                .text_for_range(next_selection.range())
14828                                .collect::<String>();
14829                            if Some(next_selected_text) != selected_text {
14830                                same_text_selected = false;
14831                                selected_text = None;
14832                            }
14833                        } else {
14834                            same_text_selected = false;
14835                            selected_text = None;
14836                        }
14837                    }
14838                }
14839            }
14840
14841            if only_carets {
14842                for selection in &mut selections {
14843                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
14844                    selection.start = word_range.start;
14845                    selection.end = word_range.end;
14846                    selection.goal = SelectionGoal::None;
14847                    selection.reversed = false;
14848                    self.select_match_ranges(
14849                        selection.start..selection.end,
14850                        selection.reversed,
14851                        action.replace_newest,
14852                        Some(Autoscroll::newest()),
14853                        window,
14854                        cx,
14855                    );
14856                }
14857                if selections.len() == 1 {
14858                    let selection = selections
14859                        .last()
14860                        .expect("ensured that there's only one selection");
14861                    let query = buffer
14862                        .text_for_range(selection.start..selection.end)
14863                        .collect::<String>();
14864                    let is_empty = query.is_empty();
14865                    let select_state = SelectNextState {
14866                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
14867                        wordwise: true,
14868                        done: is_empty,
14869                    };
14870                    self.select_prev_state = Some(select_state);
14871                } else {
14872                    self.select_prev_state = None;
14873                }
14874            } else if let Some(selected_text) = selected_text {
14875                self.select_prev_state = Some(SelectNextState {
14876                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
14877                    wordwise: false,
14878                    done: false,
14879                });
14880                self.select_previous(action, window, cx)?;
14881            }
14882        }
14883        Ok(())
14884    }
14885
14886    pub fn find_next_match(
14887        &mut self,
14888        _: &FindNextMatch,
14889        window: &mut Window,
14890        cx: &mut Context<Self>,
14891    ) -> Result<()> {
14892        let selections = self.selections.disjoint_anchors_arc();
14893        match selections.first() {
14894            Some(first) if selections.len() >= 2 => {
14895                self.change_selections(Default::default(), window, cx, |s| {
14896                    s.select_ranges([first.range()]);
14897                });
14898            }
14899            _ => self.select_next(
14900                &SelectNext {
14901                    replace_newest: true,
14902                },
14903                window,
14904                cx,
14905            )?,
14906        }
14907        Ok(())
14908    }
14909
14910    pub fn find_previous_match(
14911        &mut self,
14912        _: &FindPreviousMatch,
14913        window: &mut Window,
14914        cx: &mut Context<Self>,
14915    ) -> Result<()> {
14916        let selections = self.selections.disjoint_anchors_arc();
14917        match selections.last() {
14918            Some(last) if selections.len() >= 2 => {
14919                self.change_selections(Default::default(), window, cx, |s| {
14920                    s.select_ranges([last.range()]);
14921                });
14922            }
14923            _ => self.select_previous(
14924                &SelectPrevious {
14925                    replace_newest: true,
14926                },
14927                window,
14928                cx,
14929            )?,
14930        }
14931        Ok(())
14932    }
14933
14934    pub fn toggle_comments(
14935        &mut self,
14936        action: &ToggleComments,
14937        window: &mut Window,
14938        cx: &mut Context<Self>,
14939    ) {
14940        if self.read_only(cx) {
14941            return;
14942        }
14943        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14944        let text_layout_details = &self.text_layout_details(window);
14945        self.transact(window, cx, |this, window, cx| {
14946            let mut selections = this
14947                .selections
14948                .all::<MultiBufferPoint>(&this.display_snapshot(cx));
14949            let mut edits = Vec::new();
14950            let mut selection_edit_ranges = Vec::new();
14951            let mut last_toggled_row = None;
14952            let snapshot = this.buffer.read(cx).read(cx);
14953            let empty_str: Arc<str> = Arc::default();
14954            let mut suffixes_inserted = Vec::new();
14955            let ignore_indent = action.ignore_indent;
14956
14957            fn comment_prefix_range(
14958                snapshot: &MultiBufferSnapshot,
14959                row: MultiBufferRow,
14960                comment_prefix: &str,
14961                comment_prefix_whitespace: &str,
14962                ignore_indent: bool,
14963            ) -> Range<Point> {
14964                let indent_size = if ignore_indent {
14965                    0
14966                } else {
14967                    snapshot.indent_size_for_line(row).len
14968                };
14969
14970                let start = Point::new(row.0, indent_size);
14971
14972                let mut line_bytes = snapshot
14973                    .bytes_in_range(start..snapshot.max_point())
14974                    .flatten()
14975                    .copied();
14976
14977                // If this line currently begins with the line comment prefix, then record
14978                // the range containing the prefix.
14979                if line_bytes
14980                    .by_ref()
14981                    .take(comment_prefix.len())
14982                    .eq(comment_prefix.bytes())
14983                {
14984                    // Include any whitespace that matches the comment prefix.
14985                    let matching_whitespace_len = line_bytes
14986                        .zip(comment_prefix_whitespace.bytes())
14987                        .take_while(|(a, b)| a == b)
14988                        .count() as u32;
14989                    let end = Point::new(
14990                        start.row,
14991                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
14992                    );
14993                    start..end
14994                } else {
14995                    start..start
14996                }
14997            }
14998
14999            fn comment_suffix_range(
15000                snapshot: &MultiBufferSnapshot,
15001                row: MultiBufferRow,
15002                comment_suffix: &str,
15003                comment_suffix_has_leading_space: bool,
15004            ) -> Range<Point> {
15005                let end = Point::new(row.0, snapshot.line_len(row));
15006                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
15007
15008                let mut line_end_bytes = snapshot
15009                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
15010                    .flatten()
15011                    .copied();
15012
15013                let leading_space_len = if suffix_start_column > 0
15014                    && line_end_bytes.next() == Some(b' ')
15015                    && comment_suffix_has_leading_space
15016                {
15017                    1
15018                } else {
15019                    0
15020                };
15021
15022                // If this line currently begins with the line comment prefix, then record
15023                // the range containing the prefix.
15024                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
15025                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
15026                    start..end
15027                } else {
15028                    end..end
15029                }
15030            }
15031
15032            // TODO: Handle selections that cross excerpts
15033            for selection in &mut selections {
15034                let start_column = snapshot
15035                    .indent_size_for_line(MultiBufferRow(selection.start.row))
15036                    .len;
15037                let language = if let Some(language) =
15038                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
15039                {
15040                    language
15041                } else {
15042                    continue;
15043                };
15044
15045                selection_edit_ranges.clear();
15046
15047                // If multiple selections contain a given row, avoid processing that
15048                // row more than once.
15049                let mut start_row = MultiBufferRow(selection.start.row);
15050                if last_toggled_row == Some(start_row) {
15051                    start_row = start_row.next_row();
15052                }
15053                let end_row =
15054                    if selection.end.row > selection.start.row && selection.end.column == 0 {
15055                        MultiBufferRow(selection.end.row - 1)
15056                    } else {
15057                        MultiBufferRow(selection.end.row)
15058                    };
15059                last_toggled_row = Some(end_row);
15060
15061                if start_row > end_row {
15062                    continue;
15063                }
15064
15065                // If the language has line comments, toggle those.
15066                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
15067
15068                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
15069                if ignore_indent {
15070                    full_comment_prefixes = full_comment_prefixes
15071                        .into_iter()
15072                        .map(|s| Arc::from(s.trim_end()))
15073                        .collect();
15074                }
15075
15076                if !full_comment_prefixes.is_empty() {
15077                    let first_prefix = full_comment_prefixes
15078                        .first()
15079                        .expect("prefixes is non-empty");
15080                    let prefix_trimmed_lengths = full_comment_prefixes
15081                        .iter()
15082                        .map(|p| p.trim_end_matches(' ').len())
15083                        .collect::<SmallVec<[usize; 4]>>();
15084
15085                    let mut all_selection_lines_are_comments = true;
15086
15087                    for row in start_row.0..=end_row.0 {
15088                        let row = MultiBufferRow(row);
15089                        if start_row < end_row && snapshot.is_line_blank(row) {
15090                            continue;
15091                        }
15092
15093                        let prefix_range = full_comment_prefixes
15094                            .iter()
15095                            .zip(prefix_trimmed_lengths.iter().copied())
15096                            .map(|(prefix, trimmed_prefix_len)| {
15097                                comment_prefix_range(
15098                                    snapshot.deref(),
15099                                    row,
15100                                    &prefix[..trimmed_prefix_len],
15101                                    &prefix[trimmed_prefix_len..],
15102                                    ignore_indent,
15103                                )
15104                            })
15105                            .max_by_key(|range| range.end.column - range.start.column)
15106                            .expect("prefixes is non-empty");
15107
15108                        if prefix_range.is_empty() {
15109                            all_selection_lines_are_comments = false;
15110                        }
15111
15112                        selection_edit_ranges.push(prefix_range);
15113                    }
15114
15115                    if all_selection_lines_are_comments {
15116                        edits.extend(
15117                            selection_edit_ranges
15118                                .iter()
15119                                .cloned()
15120                                .map(|range| (range, empty_str.clone())),
15121                        );
15122                    } else {
15123                        let min_column = selection_edit_ranges
15124                            .iter()
15125                            .map(|range| range.start.column)
15126                            .min()
15127                            .unwrap_or(0);
15128                        edits.extend(selection_edit_ranges.iter().map(|range| {
15129                            let position = Point::new(range.start.row, min_column);
15130                            (position..position, first_prefix.clone())
15131                        }));
15132                    }
15133                } else if let Some(BlockCommentConfig {
15134                    start: full_comment_prefix,
15135                    end: comment_suffix,
15136                    ..
15137                }) = language.block_comment()
15138                {
15139                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
15140                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
15141                    let prefix_range = comment_prefix_range(
15142                        snapshot.deref(),
15143                        start_row,
15144                        comment_prefix,
15145                        comment_prefix_whitespace,
15146                        ignore_indent,
15147                    );
15148                    let suffix_range = comment_suffix_range(
15149                        snapshot.deref(),
15150                        end_row,
15151                        comment_suffix.trim_start_matches(' '),
15152                        comment_suffix.starts_with(' '),
15153                    );
15154
15155                    if prefix_range.is_empty() || suffix_range.is_empty() {
15156                        edits.push((
15157                            prefix_range.start..prefix_range.start,
15158                            full_comment_prefix.clone(),
15159                        ));
15160                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
15161                        suffixes_inserted.push((end_row, comment_suffix.len()));
15162                    } else {
15163                        edits.push((prefix_range, empty_str.clone()));
15164                        edits.push((suffix_range, empty_str.clone()));
15165                    }
15166                } else {
15167                    continue;
15168                }
15169            }
15170
15171            drop(snapshot);
15172            this.buffer.update(cx, |buffer, cx| {
15173                buffer.edit(edits, None, cx);
15174            });
15175
15176            // Adjust selections so that they end before any comment suffixes that
15177            // were inserted.
15178            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
15179            let mut selections = this.selections.all::<Point>(&this.display_snapshot(cx));
15180            let snapshot = this.buffer.read(cx).read(cx);
15181            for selection in &mut selections {
15182                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
15183                    match row.cmp(&MultiBufferRow(selection.end.row)) {
15184                        Ordering::Less => {
15185                            suffixes_inserted.next();
15186                            continue;
15187                        }
15188                        Ordering::Greater => break,
15189                        Ordering::Equal => {
15190                            if selection.end.column == snapshot.line_len(row) {
15191                                if selection.is_empty() {
15192                                    selection.start.column -= suffix_len as u32;
15193                                }
15194                                selection.end.column -= suffix_len as u32;
15195                            }
15196                            break;
15197                        }
15198                    }
15199                }
15200            }
15201
15202            drop(snapshot);
15203            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
15204
15205            let selections = this.selections.all::<Point>(&this.display_snapshot(cx));
15206            let selections_on_single_row = selections.windows(2).all(|selections| {
15207                selections[0].start.row == selections[1].start.row
15208                    && selections[0].end.row == selections[1].end.row
15209                    && selections[0].start.row == selections[0].end.row
15210            });
15211            let selections_selecting = selections
15212                .iter()
15213                .any(|selection| selection.start != selection.end);
15214            let advance_downwards = action.advance_downwards
15215                && selections_on_single_row
15216                && !selections_selecting
15217                && !matches!(this.mode, EditorMode::SingleLine);
15218
15219            if advance_downwards {
15220                let snapshot = this.buffer.read(cx).snapshot(cx);
15221
15222                this.change_selections(Default::default(), window, cx, |s| {
15223                    s.move_cursors_with(|display_snapshot, display_point, _| {
15224                        let mut point = display_point.to_point(display_snapshot);
15225                        point.row += 1;
15226                        point = snapshot.clip_point(point, Bias::Left);
15227                        let display_point = point.to_display_point(display_snapshot);
15228                        let goal = SelectionGoal::HorizontalPosition(
15229                            display_snapshot
15230                                .x_for_display_point(display_point, text_layout_details)
15231                                .into(),
15232                        );
15233                        (display_point, goal)
15234                    })
15235                });
15236            }
15237        });
15238    }
15239
15240    pub fn select_enclosing_symbol(
15241        &mut self,
15242        _: &SelectEnclosingSymbol,
15243        window: &mut Window,
15244        cx: &mut Context<Self>,
15245    ) {
15246        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15247
15248        let buffer = self.buffer.read(cx).snapshot(cx);
15249        let old_selections = self
15250            .selections
15251            .all::<usize>(&self.display_snapshot(cx))
15252            .into_boxed_slice();
15253
15254        fn update_selection(
15255            selection: &Selection<usize>,
15256            buffer_snap: &MultiBufferSnapshot,
15257        ) -> Option<Selection<usize>> {
15258            let cursor = selection.head();
15259            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
15260            for symbol in symbols.iter().rev() {
15261                let start = symbol.range.start.to_offset(buffer_snap);
15262                let end = symbol.range.end.to_offset(buffer_snap);
15263                let new_range = start..end;
15264                if start < selection.start || end > selection.end {
15265                    return Some(Selection {
15266                        id: selection.id,
15267                        start: new_range.start,
15268                        end: new_range.end,
15269                        goal: SelectionGoal::None,
15270                        reversed: selection.reversed,
15271                    });
15272                }
15273            }
15274            None
15275        }
15276
15277        let mut selected_larger_symbol = false;
15278        let new_selections = old_selections
15279            .iter()
15280            .map(|selection| match update_selection(selection, &buffer) {
15281                Some(new_selection) => {
15282                    if new_selection.range() != selection.range() {
15283                        selected_larger_symbol = true;
15284                    }
15285                    new_selection
15286                }
15287                None => selection.clone(),
15288            })
15289            .collect::<Vec<_>>();
15290
15291        if selected_larger_symbol {
15292            self.change_selections(Default::default(), window, cx, |s| {
15293                s.select(new_selections);
15294            });
15295        }
15296    }
15297
15298    pub fn select_larger_syntax_node(
15299        &mut self,
15300        _: &SelectLargerSyntaxNode,
15301        window: &mut Window,
15302        cx: &mut Context<Self>,
15303    ) {
15304        let Some(visible_row_count) = self.visible_row_count() else {
15305            return;
15306        };
15307        let old_selections: Box<[_]> = self
15308            .selections
15309            .all::<usize>(&self.display_snapshot(cx))
15310            .into();
15311        if old_selections.is_empty() {
15312            return;
15313        }
15314
15315        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15316
15317        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15318        let buffer = self.buffer.read(cx).snapshot(cx);
15319
15320        let mut selected_larger_node = false;
15321        let mut new_selections = old_selections
15322            .iter()
15323            .map(|selection| {
15324                let old_range = selection.start..selection.end;
15325
15326                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
15327                    // manually select word at selection
15328                    if ["string_content", "inline"].contains(&node.kind()) {
15329                        let (word_range, _) = buffer.surrounding_word(old_range.start, None);
15330                        // ignore if word is already selected
15331                        if !word_range.is_empty() && old_range != word_range {
15332                            let (last_word_range, _) = buffer.surrounding_word(old_range.end, None);
15333                            // only select word if start and end point belongs to same word
15334                            if word_range == last_word_range {
15335                                selected_larger_node = true;
15336                                return Selection {
15337                                    id: selection.id,
15338                                    start: word_range.start,
15339                                    end: word_range.end,
15340                                    goal: SelectionGoal::None,
15341                                    reversed: selection.reversed,
15342                                };
15343                            }
15344                        }
15345                    }
15346                }
15347
15348                let mut new_range = old_range.clone();
15349                while let Some((node, range)) = buffer.syntax_ancestor(new_range.clone()) {
15350                    new_range = range;
15351                    if !node.is_named() {
15352                        continue;
15353                    }
15354                    if !display_map.intersects_fold(new_range.start)
15355                        && !display_map.intersects_fold(new_range.end)
15356                    {
15357                        break;
15358                    }
15359                }
15360
15361                selected_larger_node |= new_range != old_range;
15362                Selection {
15363                    id: selection.id,
15364                    start: new_range.start,
15365                    end: new_range.end,
15366                    goal: SelectionGoal::None,
15367                    reversed: selection.reversed,
15368                }
15369            })
15370            .collect::<Vec<_>>();
15371
15372        if !selected_larger_node {
15373            return; // don't put this call in the history
15374        }
15375
15376        // scroll based on transformation done to the last selection created by the user
15377        let (last_old, last_new) = old_selections
15378            .last()
15379            .zip(new_selections.last().cloned())
15380            .expect("old_selections isn't empty");
15381
15382        // revert selection
15383        let is_selection_reversed = {
15384            let should_newest_selection_be_reversed = last_old.start != last_new.start;
15385            new_selections.last_mut().expect("checked above").reversed =
15386                should_newest_selection_be_reversed;
15387            should_newest_selection_be_reversed
15388        };
15389
15390        if selected_larger_node {
15391            self.select_syntax_node_history.disable_clearing = true;
15392            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15393                s.select(new_selections.clone());
15394            });
15395            self.select_syntax_node_history.disable_clearing = false;
15396        }
15397
15398        let start_row = last_new.start.to_display_point(&display_map).row().0;
15399        let end_row = last_new.end.to_display_point(&display_map).row().0;
15400        let selection_height = end_row - start_row + 1;
15401        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
15402
15403        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
15404        let scroll_behavior = if fits_on_the_screen {
15405            self.request_autoscroll(Autoscroll::fit(), cx);
15406            SelectSyntaxNodeScrollBehavior::FitSelection
15407        } else if is_selection_reversed {
15408            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15409            SelectSyntaxNodeScrollBehavior::CursorTop
15410        } else {
15411            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15412            SelectSyntaxNodeScrollBehavior::CursorBottom
15413        };
15414
15415        self.select_syntax_node_history.push((
15416            old_selections,
15417            scroll_behavior,
15418            is_selection_reversed,
15419        ));
15420    }
15421
15422    pub fn select_smaller_syntax_node(
15423        &mut self,
15424        _: &SelectSmallerSyntaxNode,
15425        window: &mut Window,
15426        cx: &mut Context<Self>,
15427    ) {
15428        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15429
15430        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
15431            self.select_syntax_node_history.pop()
15432        {
15433            if let Some(selection) = selections.last_mut() {
15434                selection.reversed = is_selection_reversed;
15435            }
15436
15437            self.select_syntax_node_history.disable_clearing = true;
15438            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15439                s.select(selections.to_vec());
15440            });
15441            self.select_syntax_node_history.disable_clearing = false;
15442
15443            match scroll_behavior {
15444                SelectSyntaxNodeScrollBehavior::CursorTop => {
15445                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15446                }
15447                SelectSyntaxNodeScrollBehavior::FitSelection => {
15448                    self.request_autoscroll(Autoscroll::fit(), cx);
15449                }
15450                SelectSyntaxNodeScrollBehavior::CursorBottom => {
15451                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15452                }
15453            }
15454        }
15455    }
15456
15457    pub fn unwrap_syntax_node(
15458        &mut self,
15459        _: &UnwrapSyntaxNode,
15460        window: &mut Window,
15461        cx: &mut Context<Self>,
15462    ) {
15463        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15464
15465        let buffer = self.buffer.read(cx).snapshot(cx);
15466        let selections = self
15467            .selections
15468            .all::<usize>(&self.display_snapshot(cx))
15469            .into_iter()
15470            // subtracting the offset requires sorting
15471            .sorted_by_key(|i| i.start);
15472
15473        let full_edits = selections
15474            .into_iter()
15475            .filter_map(|selection| {
15476                let child = if selection.is_empty()
15477                    && let Some((_, ancestor_range)) =
15478                        buffer.syntax_ancestor(selection.start..selection.end)
15479                {
15480                    ancestor_range
15481                } else {
15482                    selection.range()
15483                };
15484
15485                let mut parent = child.clone();
15486                while let Some((_, ancestor_range)) = buffer.syntax_ancestor(parent.clone()) {
15487                    parent = ancestor_range;
15488                    if parent.start < child.start || parent.end > child.end {
15489                        break;
15490                    }
15491                }
15492
15493                if parent == child {
15494                    return None;
15495                }
15496                let text = buffer.text_for_range(child).collect::<String>();
15497                Some((selection.id, parent, text))
15498            })
15499            .collect::<Vec<_>>();
15500        if full_edits.is_empty() {
15501            return;
15502        }
15503
15504        self.transact(window, cx, |this, window, cx| {
15505            this.buffer.update(cx, |buffer, cx| {
15506                buffer.edit(
15507                    full_edits
15508                        .iter()
15509                        .map(|(_, p, t)| (p.clone(), t.clone()))
15510                        .collect::<Vec<_>>(),
15511                    None,
15512                    cx,
15513                );
15514            });
15515            this.change_selections(Default::default(), window, cx, |s| {
15516                let mut offset = 0;
15517                let mut selections = vec![];
15518                for (id, parent, text) in full_edits {
15519                    let start = parent.start - offset;
15520                    offset += parent.len() - text.len();
15521                    selections.push(Selection {
15522                        id,
15523                        start,
15524                        end: start + text.len(),
15525                        reversed: false,
15526                        goal: Default::default(),
15527                    });
15528                }
15529                s.select(selections);
15530            });
15531        });
15532    }
15533
15534    pub fn select_next_syntax_node(
15535        &mut self,
15536        _: &SelectNextSyntaxNode,
15537        window: &mut Window,
15538        cx: &mut Context<Self>,
15539    ) {
15540        let old_selections: Box<[_]> = self
15541            .selections
15542            .all::<usize>(&self.display_snapshot(cx))
15543            .into();
15544        if old_selections.is_empty() {
15545            return;
15546        }
15547
15548        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15549
15550        let buffer = self.buffer.read(cx).snapshot(cx);
15551        let mut selected_sibling = false;
15552
15553        let new_selections = old_selections
15554            .iter()
15555            .map(|selection| {
15556                let old_range = selection.start..selection.end;
15557
15558                if let Some(node) = buffer.syntax_next_sibling(old_range) {
15559                    let new_range = node.byte_range();
15560                    selected_sibling = true;
15561                    Selection {
15562                        id: selection.id,
15563                        start: new_range.start,
15564                        end: new_range.end,
15565                        goal: SelectionGoal::None,
15566                        reversed: selection.reversed,
15567                    }
15568                } else {
15569                    selection.clone()
15570                }
15571            })
15572            .collect::<Vec<_>>();
15573
15574        if selected_sibling {
15575            self.change_selections(
15576                SelectionEffects::scroll(Autoscroll::fit()),
15577                window,
15578                cx,
15579                |s| {
15580                    s.select(new_selections);
15581                },
15582            );
15583        }
15584    }
15585
15586    pub fn select_prev_syntax_node(
15587        &mut self,
15588        _: &SelectPreviousSyntaxNode,
15589        window: &mut Window,
15590        cx: &mut Context<Self>,
15591    ) {
15592        let old_selections: Box<[_]> = self
15593            .selections
15594            .all::<usize>(&self.display_snapshot(cx))
15595            .into();
15596        if old_selections.is_empty() {
15597            return;
15598        }
15599
15600        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15601
15602        let buffer = self.buffer.read(cx).snapshot(cx);
15603        let mut selected_sibling = false;
15604
15605        let new_selections = old_selections
15606            .iter()
15607            .map(|selection| {
15608                let old_range = selection.start..selection.end;
15609
15610                if let Some(node) = buffer.syntax_prev_sibling(old_range) {
15611                    let new_range = node.byte_range();
15612                    selected_sibling = true;
15613                    Selection {
15614                        id: selection.id,
15615                        start: new_range.start,
15616                        end: new_range.end,
15617                        goal: SelectionGoal::None,
15618                        reversed: selection.reversed,
15619                    }
15620                } else {
15621                    selection.clone()
15622                }
15623            })
15624            .collect::<Vec<_>>();
15625
15626        if selected_sibling {
15627            self.change_selections(
15628                SelectionEffects::scroll(Autoscroll::fit()),
15629                window,
15630                cx,
15631                |s| {
15632                    s.select(new_selections);
15633                },
15634            );
15635        }
15636    }
15637
15638    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
15639        if !EditorSettings::get_global(cx).gutter.runnables {
15640            self.clear_tasks();
15641            return Task::ready(());
15642        }
15643        let project = self.project().map(Entity::downgrade);
15644        let task_sources = self.lsp_task_sources(cx);
15645        let multi_buffer = self.buffer.downgrade();
15646        cx.spawn_in(window, async move |editor, cx| {
15647            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
15648            let Some(project) = project.and_then(|p| p.upgrade()) else {
15649                return;
15650            };
15651            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
15652                this.display_map.update(cx, |map, cx| map.snapshot(cx))
15653            }) else {
15654                return;
15655            };
15656
15657            let hide_runnables = project
15658                .update(cx, |project, _| project.is_via_collab())
15659                .unwrap_or(true);
15660            if hide_runnables {
15661                return;
15662            }
15663            let new_rows =
15664                cx.background_spawn({
15665                    let snapshot = display_snapshot.clone();
15666                    async move {
15667                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
15668                    }
15669                })
15670                    .await;
15671            let Ok(lsp_tasks) =
15672                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
15673            else {
15674                return;
15675            };
15676            let lsp_tasks = lsp_tasks.await;
15677
15678            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
15679                lsp_tasks
15680                    .into_iter()
15681                    .flat_map(|(kind, tasks)| {
15682                        tasks.into_iter().filter_map(move |(location, task)| {
15683                            Some((kind.clone(), location?, task))
15684                        })
15685                    })
15686                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
15687                        let buffer = location.target.buffer;
15688                        let buffer_snapshot = buffer.read(cx).snapshot();
15689                        let offset = display_snapshot.buffer_snapshot().excerpts().find_map(
15690                            |(excerpt_id, snapshot, _)| {
15691                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
15692                                    display_snapshot
15693                                        .buffer_snapshot()
15694                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
15695                                } else {
15696                                    None
15697                                }
15698                            },
15699                        );
15700                        if let Some(offset) = offset {
15701                            let task_buffer_range =
15702                                location.target.range.to_point(&buffer_snapshot);
15703                            let context_buffer_range =
15704                                task_buffer_range.to_offset(&buffer_snapshot);
15705                            let context_range = BufferOffset(context_buffer_range.start)
15706                                ..BufferOffset(context_buffer_range.end);
15707
15708                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
15709                                .or_insert_with(|| RunnableTasks {
15710                                    templates: Vec::new(),
15711                                    offset,
15712                                    column: task_buffer_range.start.column,
15713                                    extra_variables: HashMap::default(),
15714                                    context_range,
15715                                })
15716                                .templates
15717                                .push((kind, task.original_task().clone()));
15718                        }
15719
15720                        acc
15721                    })
15722            }) else {
15723                return;
15724            };
15725
15726            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
15727                buffer.language_settings(cx).tasks.prefer_lsp
15728            }) else {
15729                return;
15730            };
15731
15732            let rows = Self::runnable_rows(
15733                project,
15734                display_snapshot,
15735                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
15736                new_rows,
15737                cx.clone(),
15738            )
15739            .await;
15740            editor
15741                .update(cx, |editor, _| {
15742                    editor.clear_tasks();
15743                    for (key, mut value) in rows {
15744                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
15745                            value.templates.extend(lsp_tasks.templates);
15746                        }
15747
15748                        editor.insert_tasks(key, value);
15749                    }
15750                    for (key, value) in lsp_tasks_by_rows {
15751                        editor.insert_tasks(key, value);
15752                    }
15753                })
15754                .ok();
15755        })
15756    }
15757    fn fetch_runnable_ranges(
15758        snapshot: &DisplaySnapshot,
15759        range: Range<Anchor>,
15760    ) -> Vec<language::RunnableRange> {
15761        snapshot.buffer_snapshot().runnable_ranges(range).collect()
15762    }
15763
15764    fn runnable_rows(
15765        project: Entity<Project>,
15766        snapshot: DisplaySnapshot,
15767        prefer_lsp: bool,
15768        runnable_ranges: Vec<RunnableRange>,
15769        cx: AsyncWindowContext,
15770    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
15771        cx.spawn(async move |cx| {
15772            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
15773            for mut runnable in runnable_ranges {
15774                let Some(tasks) = cx
15775                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
15776                    .ok()
15777                else {
15778                    continue;
15779                };
15780                let mut tasks = tasks.await;
15781
15782                if prefer_lsp {
15783                    tasks.retain(|(task_kind, _)| {
15784                        !matches!(task_kind, TaskSourceKind::Language { .. })
15785                    });
15786                }
15787                if tasks.is_empty() {
15788                    continue;
15789                }
15790
15791                let point = runnable
15792                    .run_range
15793                    .start
15794                    .to_point(&snapshot.buffer_snapshot());
15795                let Some(row) = snapshot
15796                    .buffer_snapshot()
15797                    .buffer_line_for_row(MultiBufferRow(point.row))
15798                    .map(|(_, range)| range.start.row)
15799                else {
15800                    continue;
15801                };
15802
15803                let context_range =
15804                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
15805                runnable_rows.push((
15806                    (runnable.buffer_id, row),
15807                    RunnableTasks {
15808                        templates: tasks,
15809                        offset: snapshot
15810                            .buffer_snapshot()
15811                            .anchor_before(runnable.run_range.start),
15812                        context_range,
15813                        column: point.column,
15814                        extra_variables: runnable.extra_captures,
15815                    },
15816                ));
15817            }
15818            runnable_rows
15819        })
15820    }
15821
15822    fn templates_with_tags(
15823        project: &Entity<Project>,
15824        runnable: &mut Runnable,
15825        cx: &mut App,
15826    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
15827        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
15828            let (worktree_id, file) = project
15829                .buffer_for_id(runnable.buffer, cx)
15830                .and_then(|buffer| buffer.read(cx).file())
15831                .map(|file| (file.worktree_id(cx), file.clone()))
15832                .unzip();
15833
15834            (
15835                project.task_store().read(cx).task_inventory().cloned(),
15836                worktree_id,
15837                file,
15838            )
15839        });
15840
15841        let tags = mem::take(&mut runnable.tags);
15842        let language = runnable.language.clone();
15843        cx.spawn(async move |cx| {
15844            let mut templates_with_tags = Vec::new();
15845            if let Some(inventory) = inventory {
15846                for RunnableTag(tag) in tags {
15847                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
15848                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
15849                    }) else {
15850                        return templates_with_tags;
15851                    };
15852                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
15853                        move |(_, template)| {
15854                            template.tags.iter().any(|source_tag| source_tag == &tag)
15855                        },
15856                    ));
15857                }
15858            }
15859            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
15860
15861            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
15862                // Strongest source wins; if we have worktree tag binding, prefer that to
15863                // global and language bindings;
15864                // if we have a global binding, prefer that to language binding.
15865                let first_mismatch = templates_with_tags
15866                    .iter()
15867                    .position(|(tag_source, _)| tag_source != leading_tag_source);
15868                if let Some(index) = first_mismatch {
15869                    templates_with_tags.truncate(index);
15870                }
15871            }
15872
15873            templates_with_tags
15874        })
15875    }
15876
15877    pub fn move_to_enclosing_bracket(
15878        &mut self,
15879        _: &MoveToEnclosingBracket,
15880        window: &mut Window,
15881        cx: &mut Context<Self>,
15882    ) {
15883        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15884        self.change_selections(Default::default(), window, cx, |s| {
15885            s.move_offsets_with(|snapshot, selection| {
15886                let Some(enclosing_bracket_ranges) =
15887                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
15888                else {
15889                    return;
15890                };
15891
15892                let mut best_length = usize::MAX;
15893                let mut best_inside = false;
15894                let mut best_in_bracket_range = false;
15895                let mut best_destination = None;
15896                for (open, close) in enclosing_bracket_ranges {
15897                    let close = close.to_inclusive();
15898                    let length = close.end() - open.start;
15899                    let inside = selection.start >= open.end && selection.end <= *close.start();
15900                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
15901                        || close.contains(&selection.head());
15902
15903                    // If best is next to a bracket and current isn't, skip
15904                    if !in_bracket_range && best_in_bracket_range {
15905                        continue;
15906                    }
15907
15908                    // Prefer smaller lengths unless best is inside and current isn't
15909                    if length > best_length && (best_inside || !inside) {
15910                        continue;
15911                    }
15912
15913                    best_length = length;
15914                    best_inside = inside;
15915                    best_in_bracket_range = in_bracket_range;
15916                    best_destination = Some(
15917                        if close.contains(&selection.start) && close.contains(&selection.end) {
15918                            if inside { open.end } else { open.start }
15919                        } else if inside {
15920                            *close.start()
15921                        } else {
15922                            *close.end()
15923                        },
15924                    );
15925                }
15926
15927                if let Some(destination) = best_destination {
15928                    selection.collapse_to(destination, SelectionGoal::None);
15929                }
15930            })
15931        });
15932    }
15933
15934    pub fn undo_selection(
15935        &mut self,
15936        _: &UndoSelection,
15937        window: &mut Window,
15938        cx: &mut Context<Self>,
15939    ) {
15940        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15941        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
15942            self.selection_history.mode = SelectionHistoryMode::Undoing;
15943            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15944                this.end_selection(window, cx);
15945                this.change_selections(
15946                    SelectionEffects::scroll(Autoscroll::newest()),
15947                    window,
15948                    cx,
15949                    |s| s.select_anchors(entry.selections.to_vec()),
15950                );
15951            });
15952            self.selection_history.mode = SelectionHistoryMode::Normal;
15953
15954            self.select_next_state = entry.select_next_state;
15955            self.select_prev_state = entry.select_prev_state;
15956            self.add_selections_state = entry.add_selections_state;
15957        }
15958    }
15959
15960    pub fn redo_selection(
15961        &mut self,
15962        _: &RedoSelection,
15963        window: &mut Window,
15964        cx: &mut Context<Self>,
15965    ) {
15966        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15967        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
15968            self.selection_history.mode = SelectionHistoryMode::Redoing;
15969            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15970                this.end_selection(window, cx);
15971                this.change_selections(
15972                    SelectionEffects::scroll(Autoscroll::newest()),
15973                    window,
15974                    cx,
15975                    |s| s.select_anchors(entry.selections.to_vec()),
15976                );
15977            });
15978            self.selection_history.mode = SelectionHistoryMode::Normal;
15979
15980            self.select_next_state = entry.select_next_state;
15981            self.select_prev_state = entry.select_prev_state;
15982            self.add_selections_state = entry.add_selections_state;
15983        }
15984    }
15985
15986    pub fn expand_excerpts(
15987        &mut self,
15988        action: &ExpandExcerpts,
15989        _: &mut Window,
15990        cx: &mut Context<Self>,
15991    ) {
15992        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
15993    }
15994
15995    pub fn expand_excerpts_down(
15996        &mut self,
15997        action: &ExpandExcerptsDown,
15998        _: &mut Window,
15999        cx: &mut Context<Self>,
16000    ) {
16001        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
16002    }
16003
16004    pub fn expand_excerpts_up(
16005        &mut self,
16006        action: &ExpandExcerptsUp,
16007        _: &mut Window,
16008        cx: &mut Context<Self>,
16009    ) {
16010        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
16011    }
16012
16013    pub fn expand_excerpts_for_direction(
16014        &mut self,
16015        lines: u32,
16016        direction: ExpandExcerptDirection,
16017
16018        cx: &mut Context<Self>,
16019    ) {
16020        let selections = self.selections.disjoint_anchors_arc();
16021
16022        let lines = if lines == 0 {
16023            EditorSettings::get_global(cx).expand_excerpt_lines
16024        } else {
16025            lines
16026        };
16027
16028        self.buffer.update(cx, |buffer, cx| {
16029            let snapshot = buffer.snapshot(cx);
16030            let mut excerpt_ids = selections
16031                .iter()
16032                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
16033                .collect::<Vec<_>>();
16034            excerpt_ids.sort();
16035            excerpt_ids.dedup();
16036            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
16037        })
16038    }
16039
16040    pub fn expand_excerpt(
16041        &mut self,
16042        excerpt: ExcerptId,
16043        direction: ExpandExcerptDirection,
16044        window: &mut Window,
16045        cx: &mut Context<Self>,
16046    ) {
16047        let current_scroll_position = self.scroll_position(cx);
16048        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
16049        let mut scroll = None;
16050
16051        if direction == ExpandExcerptDirection::Down {
16052            let multi_buffer = self.buffer.read(cx);
16053            let snapshot = multi_buffer.snapshot(cx);
16054            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt)
16055                && let Some(buffer) = multi_buffer.buffer(buffer_id)
16056                && let Some(excerpt_range) = snapshot.context_range_for_excerpt(excerpt)
16057            {
16058                let buffer_snapshot = buffer.read(cx).snapshot();
16059                let excerpt_end_row = Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
16060                let last_row = buffer_snapshot.max_point().row;
16061                let lines_below = last_row.saturating_sub(excerpt_end_row);
16062                if lines_below >= lines_to_expand {
16063                    scroll = Some(
16064                        current_scroll_position
16065                            + gpui::Point::new(0.0, lines_to_expand as ScrollOffset),
16066                    );
16067                }
16068            }
16069        }
16070        if direction == ExpandExcerptDirection::Up
16071            && self
16072                .buffer
16073                .read(cx)
16074                .snapshot(cx)
16075                .excerpt_before(excerpt)
16076                .is_none()
16077        {
16078            scroll = Some(current_scroll_position);
16079        }
16080
16081        self.buffer.update(cx, |buffer, cx| {
16082            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
16083        });
16084
16085        if let Some(new_scroll_position) = scroll {
16086            self.set_scroll_position(new_scroll_position, window, cx);
16087        }
16088    }
16089
16090    pub fn go_to_singleton_buffer_point(
16091        &mut self,
16092        point: Point,
16093        window: &mut Window,
16094        cx: &mut Context<Self>,
16095    ) {
16096        self.go_to_singleton_buffer_range(point..point, window, cx);
16097    }
16098
16099    pub fn go_to_singleton_buffer_range(
16100        &mut self,
16101        range: Range<Point>,
16102        window: &mut Window,
16103        cx: &mut Context<Self>,
16104    ) {
16105        let multibuffer = self.buffer().read(cx);
16106        let Some(buffer) = multibuffer.as_singleton() else {
16107            return;
16108        };
16109        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
16110            return;
16111        };
16112        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
16113            return;
16114        };
16115        self.change_selections(
16116            SelectionEffects::default().nav_history(true),
16117            window,
16118            cx,
16119            |s| s.select_anchor_ranges([start..end]),
16120        );
16121    }
16122
16123    pub fn go_to_diagnostic(
16124        &mut self,
16125        action: &GoToDiagnostic,
16126        window: &mut Window,
16127        cx: &mut Context<Self>,
16128    ) {
16129        if !self.diagnostics_enabled() {
16130            return;
16131        }
16132        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16133        self.go_to_diagnostic_impl(Direction::Next, action.severity, window, cx)
16134    }
16135
16136    pub fn go_to_prev_diagnostic(
16137        &mut self,
16138        action: &GoToPreviousDiagnostic,
16139        window: &mut Window,
16140        cx: &mut Context<Self>,
16141    ) {
16142        if !self.diagnostics_enabled() {
16143            return;
16144        }
16145        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16146        self.go_to_diagnostic_impl(Direction::Prev, action.severity, window, cx)
16147    }
16148
16149    pub fn go_to_diagnostic_impl(
16150        &mut self,
16151        direction: Direction,
16152        severity: GoToDiagnosticSeverityFilter,
16153        window: &mut Window,
16154        cx: &mut Context<Self>,
16155    ) {
16156        let buffer = self.buffer.read(cx).snapshot(cx);
16157        let selection = self.selections.newest::<usize>(&self.display_snapshot(cx));
16158
16159        let mut active_group_id = None;
16160        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics
16161            && active_group.active_range.start.to_offset(&buffer) == selection.start
16162        {
16163            active_group_id = Some(active_group.group_id);
16164        }
16165
16166        fn filtered<'a>(
16167            severity: GoToDiagnosticSeverityFilter,
16168            diagnostics: impl Iterator<Item = DiagnosticEntryRef<'a, usize>>,
16169        ) -> impl Iterator<Item = DiagnosticEntryRef<'a, usize>> {
16170            diagnostics
16171                .filter(move |entry| severity.matches(entry.diagnostic.severity))
16172                .filter(|entry| entry.range.start != entry.range.end)
16173                .filter(|entry| !entry.diagnostic.is_unnecessary)
16174        }
16175
16176        let before = filtered(
16177            severity,
16178            buffer
16179                .diagnostics_in_range(0..selection.start)
16180                .filter(|entry| entry.range.start <= selection.start),
16181        );
16182        let after = filtered(
16183            severity,
16184            buffer
16185                .diagnostics_in_range(selection.start..buffer.len())
16186                .filter(|entry| entry.range.start >= selection.start),
16187        );
16188
16189        let mut found: Option<DiagnosticEntryRef<usize>> = None;
16190        if direction == Direction::Prev {
16191            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
16192            {
16193                for diagnostic in prev_diagnostics.into_iter().rev() {
16194                    if diagnostic.range.start != selection.start
16195                        || active_group_id
16196                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
16197                    {
16198                        found = Some(diagnostic);
16199                        break 'outer;
16200                    }
16201                }
16202            }
16203        } else {
16204            for diagnostic in after.chain(before) {
16205                if diagnostic.range.start != selection.start
16206                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
16207                {
16208                    found = Some(diagnostic);
16209                    break;
16210                }
16211            }
16212        }
16213        let Some(next_diagnostic) = found else {
16214            return;
16215        };
16216
16217        let next_diagnostic_start = buffer.anchor_after(next_diagnostic.range.start);
16218        let Some(buffer_id) = buffer.buffer_id_for_anchor(next_diagnostic_start) else {
16219            return;
16220        };
16221        let snapshot = self.snapshot(window, cx);
16222        if snapshot.intersects_fold(next_diagnostic.range.start) {
16223            self.unfold_ranges(
16224                std::slice::from_ref(&next_diagnostic.range),
16225                true,
16226                false,
16227                cx,
16228            );
16229        }
16230        self.change_selections(Default::default(), window, cx, |s| {
16231            s.select_ranges(vec![
16232                next_diagnostic.range.start..next_diagnostic.range.start,
16233            ])
16234        });
16235        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
16236        self.refresh_edit_prediction(false, true, window, cx);
16237    }
16238
16239    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
16240        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16241        let snapshot = self.snapshot(window, cx);
16242        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
16243        self.go_to_hunk_before_or_after_position(
16244            &snapshot,
16245            selection.head(),
16246            Direction::Next,
16247            window,
16248            cx,
16249        );
16250    }
16251
16252    pub fn go_to_hunk_before_or_after_position(
16253        &mut self,
16254        snapshot: &EditorSnapshot,
16255        position: Point,
16256        direction: Direction,
16257        window: &mut Window,
16258        cx: &mut Context<Editor>,
16259    ) {
16260        let row = if direction == Direction::Next {
16261            self.hunk_after_position(snapshot, position)
16262                .map(|hunk| hunk.row_range.start)
16263        } else {
16264            self.hunk_before_position(snapshot, position)
16265        };
16266
16267        if let Some(row) = row {
16268            let destination = Point::new(row.0, 0);
16269            let autoscroll = Autoscroll::center();
16270
16271            self.unfold_ranges(&[destination..destination], false, false, cx);
16272            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16273                s.select_ranges([destination..destination]);
16274            });
16275        }
16276    }
16277
16278    fn hunk_after_position(
16279        &mut self,
16280        snapshot: &EditorSnapshot,
16281        position: Point,
16282    ) -> Option<MultiBufferDiffHunk> {
16283        snapshot
16284            .buffer_snapshot()
16285            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
16286            .find(|hunk| hunk.row_range.start.0 > position.row)
16287            .or_else(|| {
16288                snapshot
16289                    .buffer_snapshot()
16290                    .diff_hunks_in_range(Point::zero()..position)
16291                    .find(|hunk| hunk.row_range.end.0 < position.row)
16292            })
16293    }
16294
16295    fn go_to_prev_hunk(
16296        &mut self,
16297        _: &GoToPreviousHunk,
16298        window: &mut Window,
16299        cx: &mut Context<Self>,
16300    ) {
16301        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16302        let snapshot = self.snapshot(window, cx);
16303        let selection = self.selections.newest::<Point>(&snapshot.display_snapshot);
16304        self.go_to_hunk_before_or_after_position(
16305            &snapshot,
16306            selection.head(),
16307            Direction::Prev,
16308            window,
16309            cx,
16310        );
16311    }
16312
16313    fn hunk_before_position(
16314        &mut self,
16315        snapshot: &EditorSnapshot,
16316        position: Point,
16317    ) -> Option<MultiBufferRow> {
16318        snapshot
16319            .buffer_snapshot()
16320            .diff_hunk_before(position)
16321            .or_else(|| snapshot.buffer_snapshot().diff_hunk_before(Point::MAX))
16322    }
16323
16324    fn go_to_next_change(
16325        &mut self,
16326        _: &GoToNextChange,
16327        window: &mut Window,
16328        cx: &mut Context<Self>,
16329    ) {
16330        if let Some(selections) = self
16331            .change_list
16332            .next_change(1, Direction::Next)
16333            .map(|s| s.to_vec())
16334        {
16335            self.change_selections(Default::default(), window, cx, |s| {
16336                let map = s.display_snapshot();
16337                s.select_display_ranges(selections.iter().map(|a| {
16338                    let point = a.to_display_point(&map);
16339                    point..point
16340                }))
16341            })
16342        }
16343    }
16344
16345    fn go_to_previous_change(
16346        &mut self,
16347        _: &GoToPreviousChange,
16348        window: &mut Window,
16349        cx: &mut Context<Self>,
16350    ) {
16351        if let Some(selections) = self
16352            .change_list
16353            .next_change(1, Direction::Prev)
16354            .map(|s| s.to_vec())
16355        {
16356            self.change_selections(Default::default(), window, cx, |s| {
16357                let map = s.display_snapshot();
16358                s.select_display_ranges(selections.iter().map(|a| {
16359                    let point = a.to_display_point(&map);
16360                    point..point
16361                }))
16362            })
16363        }
16364    }
16365
16366    pub fn go_to_next_document_highlight(
16367        &mut self,
16368        _: &GoToNextDocumentHighlight,
16369        window: &mut Window,
16370        cx: &mut Context<Self>,
16371    ) {
16372        self.go_to_document_highlight_before_or_after_position(Direction::Next, window, cx);
16373    }
16374
16375    pub fn go_to_prev_document_highlight(
16376        &mut self,
16377        _: &GoToPreviousDocumentHighlight,
16378        window: &mut Window,
16379        cx: &mut Context<Self>,
16380    ) {
16381        self.go_to_document_highlight_before_or_after_position(Direction::Prev, window, cx);
16382    }
16383
16384    pub fn go_to_document_highlight_before_or_after_position(
16385        &mut self,
16386        direction: Direction,
16387        window: &mut Window,
16388        cx: &mut Context<Editor>,
16389    ) {
16390        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16391        let snapshot = self.snapshot(window, cx);
16392        let buffer = &snapshot.buffer_snapshot();
16393        let position = self
16394            .selections
16395            .newest::<Point>(&snapshot.display_snapshot)
16396            .head();
16397        let anchor_position = buffer.anchor_after(position);
16398
16399        // Get all document highlights (both read and write)
16400        let mut all_highlights = Vec::new();
16401
16402        if let Some((_, read_highlights)) = self
16403            .background_highlights
16404            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
16405        {
16406            all_highlights.extend(read_highlights.iter());
16407        }
16408
16409        if let Some((_, write_highlights)) = self
16410            .background_highlights
16411            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
16412        {
16413            all_highlights.extend(write_highlights.iter());
16414        }
16415
16416        if all_highlights.is_empty() {
16417            return;
16418        }
16419
16420        // Sort highlights by position
16421        all_highlights.sort_by(|a, b| a.start.cmp(&b.start, buffer));
16422
16423        let target_highlight = match direction {
16424            Direction::Next => {
16425                // Find the first highlight after the current position
16426                all_highlights
16427                    .iter()
16428                    .find(|highlight| highlight.start.cmp(&anchor_position, buffer).is_gt())
16429            }
16430            Direction::Prev => {
16431                // Find the last highlight before the current position
16432                all_highlights
16433                    .iter()
16434                    .rev()
16435                    .find(|highlight| highlight.end.cmp(&anchor_position, buffer).is_lt())
16436            }
16437        };
16438
16439        if let Some(highlight) = target_highlight {
16440            let destination = highlight.start.to_point(buffer);
16441            let autoscroll = Autoscroll::center();
16442
16443            self.unfold_ranges(&[destination..destination], false, false, cx);
16444            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16445                s.select_ranges([destination..destination]);
16446            });
16447        }
16448    }
16449
16450    fn go_to_line<T: 'static>(
16451        &mut self,
16452        position: Anchor,
16453        highlight_color: Option<Hsla>,
16454        window: &mut Window,
16455        cx: &mut Context<Self>,
16456    ) {
16457        let snapshot = self.snapshot(window, cx).display_snapshot;
16458        let position = position.to_point(&snapshot.buffer_snapshot());
16459        let start = snapshot
16460            .buffer_snapshot()
16461            .clip_point(Point::new(position.row, 0), Bias::Left);
16462        let end = start + Point::new(1, 0);
16463        let start = snapshot.buffer_snapshot().anchor_before(start);
16464        let end = snapshot.buffer_snapshot().anchor_before(end);
16465
16466        self.highlight_rows::<T>(
16467            start..end,
16468            highlight_color
16469                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
16470            Default::default(),
16471            cx,
16472        );
16473
16474        if self.buffer.read(cx).is_singleton() {
16475            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
16476        }
16477    }
16478
16479    pub fn go_to_definition(
16480        &mut self,
16481        _: &GoToDefinition,
16482        window: &mut Window,
16483        cx: &mut Context<Self>,
16484    ) -> Task<Result<Navigated>> {
16485        let definition =
16486            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
16487        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
16488        cx.spawn_in(window, async move |editor, cx| {
16489            if definition.await? == Navigated::Yes {
16490                return Ok(Navigated::Yes);
16491            }
16492            match fallback_strategy {
16493                GoToDefinitionFallback::None => Ok(Navigated::No),
16494                GoToDefinitionFallback::FindAllReferences => {
16495                    match editor.update_in(cx, |editor, window, cx| {
16496                        editor.find_all_references(&FindAllReferences, window, cx)
16497                    })? {
16498                        Some(references) => references.await,
16499                        None => Ok(Navigated::No),
16500                    }
16501                }
16502            }
16503        })
16504    }
16505
16506    pub fn go_to_declaration(
16507        &mut self,
16508        _: &GoToDeclaration,
16509        window: &mut Window,
16510        cx: &mut Context<Self>,
16511    ) -> Task<Result<Navigated>> {
16512        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
16513    }
16514
16515    pub fn go_to_declaration_split(
16516        &mut self,
16517        _: &GoToDeclaration,
16518        window: &mut Window,
16519        cx: &mut Context<Self>,
16520    ) -> Task<Result<Navigated>> {
16521        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
16522    }
16523
16524    pub fn go_to_implementation(
16525        &mut self,
16526        _: &GoToImplementation,
16527        window: &mut Window,
16528        cx: &mut Context<Self>,
16529    ) -> Task<Result<Navigated>> {
16530        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
16531    }
16532
16533    pub fn go_to_implementation_split(
16534        &mut self,
16535        _: &GoToImplementationSplit,
16536        window: &mut Window,
16537        cx: &mut Context<Self>,
16538    ) -> Task<Result<Navigated>> {
16539        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
16540    }
16541
16542    pub fn go_to_type_definition(
16543        &mut self,
16544        _: &GoToTypeDefinition,
16545        window: &mut Window,
16546        cx: &mut Context<Self>,
16547    ) -> Task<Result<Navigated>> {
16548        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
16549    }
16550
16551    pub fn go_to_definition_split(
16552        &mut self,
16553        _: &GoToDefinitionSplit,
16554        window: &mut Window,
16555        cx: &mut Context<Self>,
16556    ) -> Task<Result<Navigated>> {
16557        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
16558    }
16559
16560    pub fn go_to_type_definition_split(
16561        &mut self,
16562        _: &GoToTypeDefinitionSplit,
16563        window: &mut Window,
16564        cx: &mut Context<Self>,
16565    ) -> Task<Result<Navigated>> {
16566        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
16567    }
16568
16569    fn go_to_definition_of_kind(
16570        &mut self,
16571        kind: GotoDefinitionKind,
16572        split: bool,
16573        window: &mut Window,
16574        cx: &mut Context<Self>,
16575    ) -> Task<Result<Navigated>> {
16576        let Some(provider) = self.semantics_provider.clone() else {
16577            return Task::ready(Ok(Navigated::No));
16578        };
16579        let head = self
16580            .selections
16581            .newest::<usize>(&self.display_snapshot(cx))
16582            .head();
16583        let buffer = self.buffer.read(cx);
16584        let Some((buffer, head)) = buffer.text_anchor_for_position(head, cx) else {
16585            return Task::ready(Ok(Navigated::No));
16586        };
16587        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
16588            return Task::ready(Ok(Navigated::No));
16589        };
16590
16591        cx.spawn_in(window, async move |editor, cx| {
16592            let Some(definitions) = definitions.await? else {
16593                return Ok(Navigated::No);
16594            };
16595            let navigated = editor
16596                .update_in(cx, |editor, window, cx| {
16597                    editor.navigate_to_hover_links(
16598                        Some(kind),
16599                        definitions
16600                            .into_iter()
16601                            .filter(|location| {
16602                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
16603                            })
16604                            .map(HoverLink::Text)
16605                            .collect::<Vec<_>>(),
16606                        split,
16607                        window,
16608                        cx,
16609                    )
16610                })?
16611                .await?;
16612            anyhow::Ok(navigated)
16613        })
16614    }
16615
16616    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
16617        let selection = self.selections.newest_anchor();
16618        let head = selection.head();
16619        let tail = selection.tail();
16620
16621        let Some((buffer, start_position)) =
16622            self.buffer.read(cx).text_anchor_for_position(head, cx)
16623        else {
16624            return;
16625        };
16626
16627        let end_position = if head != tail {
16628            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
16629                return;
16630            };
16631            Some(pos)
16632        } else {
16633            None
16634        };
16635
16636        let url_finder = cx.spawn_in(window, async move |_editor, cx| {
16637            let url = if let Some(end_pos) = end_position {
16638                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
16639            } else {
16640                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
16641            };
16642
16643            if let Some(url) = url {
16644                cx.update(|window, cx| {
16645                    if parse_zed_link(&url, cx).is_some() {
16646                        window.dispatch_action(Box::new(zed_actions::OpenZedUrl { url }), cx);
16647                    } else {
16648                        cx.open_url(&url);
16649                    }
16650                })?;
16651            }
16652
16653            anyhow::Ok(())
16654        });
16655
16656        url_finder.detach();
16657    }
16658
16659    pub fn open_selected_filename(
16660        &mut self,
16661        _: &OpenSelectedFilename,
16662        window: &mut Window,
16663        cx: &mut Context<Self>,
16664    ) {
16665        let Some(workspace) = self.workspace() else {
16666            return;
16667        };
16668
16669        let position = self.selections.newest_anchor().head();
16670
16671        let Some((buffer, buffer_position)) =
16672            self.buffer.read(cx).text_anchor_for_position(position, cx)
16673        else {
16674            return;
16675        };
16676
16677        let project = self.project.clone();
16678
16679        cx.spawn_in(window, async move |_, cx| {
16680            let result = find_file(&buffer, project, buffer_position, cx).await;
16681
16682            if let Some((_, path)) = result {
16683                workspace
16684                    .update_in(cx, |workspace, window, cx| {
16685                        workspace.open_resolved_path(path, window, cx)
16686                    })?
16687                    .await?;
16688            }
16689            anyhow::Ok(())
16690        })
16691        .detach();
16692    }
16693
16694    pub(crate) fn navigate_to_hover_links(
16695        &mut self,
16696        kind: Option<GotoDefinitionKind>,
16697        definitions: Vec<HoverLink>,
16698        split: bool,
16699        window: &mut Window,
16700        cx: &mut Context<Editor>,
16701    ) -> Task<Result<Navigated>> {
16702        // Separate out url and file links, we can only handle one of them at most or an arbitrary number of locations
16703        let mut first_url_or_file = None;
16704        let definitions: Vec<_> = definitions
16705            .into_iter()
16706            .filter_map(|def| match def {
16707                HoverLink::Text(link) => Some(Task::ready(anyhow::Ok(Some(link.target)))),
16708                HoverLink::InlayHint(lsp_location, server_id) => {
16709                    let computation =
16710                        self.compute_target_location(lsp_location, server_id, window, cx);
16711                    Some(cx.background_spawn(computation))
16712                }
16713                HoverLink::Url(url) => {
16714                    first_url_or_file = Some(Either::Left(url));
16715                    None
16716                }
16717                HoverLink::File(path) => {
16718                    first_url_or_file = Some(Either::Right(path));
16719                    None
16720                }
16721            })
16722            .collect();
16723
16724        let workspace = self.workspace();
16725
16726        cx.spawn_in(window, async move |editor, cx| {
16727            let locations: Vec<Location> = future::join_all(definitions)
16728                .await
16729                .into_iter()
16730                .filter_map(|location| location.transpose())
16731                .collect::<Result<_>>()
16732                .context("location tasks")?;
16733            let mut locations = cx.update(|_, cx| {
16734                locations
16735                    .into_iter()
16736                    .map(|location| {
16737                        let buffer = location.buffer.read(cx);
16738                        (location.buffer, location.range.to_point(buffer))
16739                    })
16740                    .into_group_map()
16741            })?;
16742            let mut num_locations = 0;
16743            for ranges in locations.values_mut() {
16744                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
16745                ranges.dedup();
16746                num_locations += ranges.len();
16747            }
16748
16749            if num_locations > 1 {
16750                let Some(workspace) = workspace else {
16751                    return Ok(Navigated::No);
16752                };
16753
16754                let tab_kind = match kind {
16755                    Some(GotoDefinitionKind::Implementation) => "Implementations",
16756                    Some(GotoDefinitionKind::Symbol) | None => "Definitions",
16757                    Some(GotoDefinitionKind::Declaration) => "Declarations",
16758                    Some(GotoDefinitionKind::Type) => "Types",
16759                };
16760                let title = editor
16761                    .update_in(cx, |_, _, cx| {
16762                        let target = locations
16763                            .iter()
16764                            .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
16765                            .map(|(buffer, location)| {
16766                                buffer
16767                                    .read(cx)
16768                                    .text_for_range(location.clone())
16769                                    .collect::<String>()
16770                            })
16771                            .filter(|text| !text.contains('\n'))
16772                            .unique()
16773                            .take(3)
16774                            .join(", ");
16775                        if target.is_empty() {
16776                            tab_kind.to_owned()
16777                        } else {
16778                            format!("{tab_kind} for {target}")
16779                        }
16780                    })
16781                    .context("buffer title")?;
16782
16783                let opened = workspace
16784                    .update_in(cx, |workspace, window, cx| {
16785                        Self::open_locations_in_multibuffer(
16786                            workspace,
16787                            locations,
16788                            title,
16789                            split,
16790                            MultibufferSelectionMode::First,
16791                            window,
16792                            cx,
16793                        )
16794                    })
16795                    .is_ok();
16796
16797                anyhow::Ok(Navigated::from_bool(opened))
16798            } else if num_locations == 0 {
16799                // If there is one url or file, open it directly
16800                match first_url_or_file {
16801                    Some(Either::Left(url)) => {
16802                        cx.update(|_, cx| cx.open_url(&url))?;
16803                        Ok(Navigated::Yes)
16804                    }
16805                    Some(Either::Right(path)) => {
16806                        let Some(workspace) = workspace else {
16807                            return Ok(Navigated::No);
16808                        };
16809
16810                        workspace
16811                            .update_in(cx, |workspace, window, cx| {
16812                                workspace.open_resolved_path(path, window, cx)
16813                            })?
16814                            .await?;
16815                        Ok(Navigated::Yes)
16816                    }
16817                    None => Ok(Navigated::No),
16818                }
16819            } else {
16820                let Some(workspace) = workspace else {
16821                    return Ok(Navigated::No);
16822                };
16823
16824                let (target_buffer, target_ranges) = locations.into_iter().next().unwrap();
16825                let target_range = target_ranges.first().unwrap().clone();
16826
16827                editor.update_in(cx, |editor, window, cx| {
16828                    let range = target_range.to_point(target_buffer.read(cx));
16829                    let range = editor.range_for_match(&range, false);
16830                    let range = collapse_multiline_range(range);
16831
16832                    if !split
16833                        && Some(&target_buffer) == editor.buffer.read(cx).as_singleton().as_ref()
16834                    {
16835                        editor.go_to_singleton_buffer_range(range, window, cx);
16836                    } else {
16837                        let pane = workspace.read(cx).active_pane().clone();
16838                        window.defer(cx, move |window, cx| {
16839                            let target_editor: Entity<Self> =
16840                                workspace.update(cx, |workspace, cx| {
16841                                    let pane = if split {
16842                                        workspace.adjacent_pane(window, cx)
16843                                    } else {
16844                                        workspace.active_pane().clone()
16845                                    };
16846
16847                                    workspace.open_project_item(
16848                                        pane,
16849                                        target_buffer.clone(),
16850                                        true,
16851                                        true,
16852                                        window,
16853                                        cx,
16854                                    )
16855                                });
16856                            target_editor.update(cx, |target_editor, cx| {
16857                                // When selecting a definition in a different buffer, disable the nav history
16858                                // to avoid creating a history entry at the previous cursor location.
16859                                pane.update(cx, |pane, _| pane.disable_history());
16860                                target_editor.go_to_singleton_buffer_range(range, window, cx);
16861                                pane.update(cx, |pane, _| pane.enable_history());
16862                            });
16863                        });
16864                    }
16865                    Navigated::Yes
16866                })
16867            }
16868        })
16869    }
16870
16871    fn compute_target_location(
16872        &self,
16873        lsp_location: lsp::Location,
16874        server_id: LanguageServerId,
16875        window: &mut Window,
16876        cx: &mut Context<Self>,
16877    ) -> Task<anyhow::Result<Option<Location>>> {
16878        let Some(project) = self.project.clone() else {
16879            return Task::ready(Ok(None));
16880        };
16881
16882        cx.spawn_in(window, async move |editor, cx| {
16883            let location_task = editor.update(cx, |_, cx| {
16884                project.update(cx, |project, cx| {
16885                    project.open_local_buffer_via_lsp(lsp_location.uri.clone(), server_id, cx)
16886                })
16887            })?;
16888            let location = Some({
16889                let target_buffer_handle = location_task.await.context("open local buffer")?;
16890                let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
16891                    let target_start = target_buffer
16892                        .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
16893                    let target_end = target_buffer
16894                        .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
16895                    target_buffer.anchor_after(target_start)
16896                        ..target_buffer.anchor_before(target_end)
16897                })?;
16898                Location {
16899                    buffer: target_buffer_handle,
16900                    range,
16901                }
16902            });
16903            Ok(location)
16904        })
16905    }
16906
16907    fn go_to_next_reference(
16908        &mut self,
16909        _: &GoToNextReference,
16910        window: &mut Window,
16911        cx: &mut Context<Self>,
16912    ) {
16913        let task = self.go_to_reference_before_or_after_position(Direction::Next, 1, window, cx);
16914        if let Some(task) = task {
16915            task.detach();
16916        };
16917    }
16918
16919    fn go_to_prev_reference(
16920        &mut self,
16921        _: &GoToPreviousReference,
16922        window: &mut Window,
16923        cx: &mut Context<Self>,
16924    ) {
16925        let task = self.go_to_reference_before_or_after_position(Direction::Prev, 1, window, cx);
16926        if let Some(task) = task {
16927            task.detach();
16928        };
16929    }
16930
16931    pub fn go_to_reference_before_or_after_position(
16932        &mut self,
16933        direction: Direction,
16934        count: usize,
16935        window: &mut Window,
16936        cx: &mut Context<Self>,
16937    ) -> Option<Task<Result<()>>> {
16938        let selection = self.selections.newest_anchor();
16939        let head = selection.head();
16940
16941        let multi_buffer = self.buffer.read(cx);
16942
16943        let (buffer, text_head) = multi_buffer.text_anchor_for_position(head, cx)?;
16944        let workspace = self.workspace()?;
16945        let project = workspace.read(cx).project().clone();
16946        let references =
16947            project.update(cx, |project, cx| project.references(&buffer, text_head, cx));
16948        Some(cx.spawn_in(window, async move |editor, cx| -> Result<()> {
16949            let Some(locations) = references.await? else {
16950                return Ok(());
16951            };
16952
16953            if locations.is_empty() {
16954                // totally normal - the cursor may be on something which is not
16955                // a symbol (e.g. a keyword)
16956                log::info!("no references found under cursor");
16957                return Ok(());
16958            }
16959
16960            let multi_buffer = editor.read_with(cx, |editor, _| editor.buffer().clone())?;
16961
16962            let multi_buffer_snapshot =
16963                multi_buffer.read_with(cx, |multi_buffer, cx| multi_buffer.snapshot(cx))?;
16964
16965            let (locations, current_location_index) =
16966                multi_buffer.update(cx, |multi_buffer, cx| {
16967                    let mut locations = locations
16968                        .into_iter()
16969                        .filter_map(|loc| {
16970                            let start = multi_buffer.buffer_anchor_to_anchor(
16971                                &loc.buffer,
16972                                loc.range.start,
16973                                cx,
16974                            )?;
16975                            let end = multi_buffer.buffer_anchor_to_anchor(
16976                                &loc.buffer,
16977                                loc.range.end,
16978                                cx,
16979                            )?;
16980                            Some(start..end)
16981                        })
16982                        .collect::<Vec<_>>();
16983
16984                    // There is an O(n) implementation, but given this list will be
16985                    // small (usually <100 items), the extra O(log(n)) factor isn't
16986                    // worth the (surprisingly large amount of) extra complexity.
16987                    locations
16988                        .sort_unstable_by(|l, r| l.start.cmp(&r.start, &multi_buffer_snapshot));
16989
16990                    let head_offset = head.to_offset(&multi_buffer_snapshot);
16991
16992                    let current_location_index = locations.iter().position(|loc| {
16993                        loc.start.to_offset(&multi_buffer_snapshot) <= head_offset
16994                            && loc.end.to_offset(&multi_buffer_snapshot) >= head_offset
16995                    });
16996
16997                    (locations, current_location_index)
16998                })?;
16999
17000            let Some(current_location_index) = current_location_index else {
17001                // This indicates something has gone wrong, because we already
17002                // handle the "no references" case above
17003                log::error!(
17004                    "failed to find current reference under cursor. Total references: {}",
17005                    locations.len()
17006                );
17007                return Ok(());
17008            };
17009
17010            let destination_location_index = match direction {
17011                Direction::Next => (current_location_index + count) % locations.len(),
17012                Direction::Prev => {
17013                    (current_location_index + locations.len() - count % locations.len())
17014                        % locations.len()
17015                }
17016            };
17017
17018            // TODO(cameron): is this needed?
17019            // the thinking is to avoid "jumping to the current location" (avoid
17020            // polluting "jumplist" in vim terms)
17021            if current_location_index == destination_location_index {
17022                return Ok(());
17023            }
17024
17025            let Range { start, end } = locations[destination_location_index];
17026
17027            editor.update_in(cx, |editor, window, cx| {
17028                let effects = SelectionEffects::default();
17029
17030                editor.unfold_ranges(&[start..end], false, false, cx);
17031                editor.change_selections(effects, window, cx, |s| {
17032                    s.select_ranges([start..start]);
17033                });
17034            })?;
17035
17036            Ok(())
17037        }))
17038    }
17039
17040    pub fn find_all_references(
17041        &mut self,
17042        _: &FindAllReferences,
17043        window: &mut Window,
17044        cx: &mut Context<Self>,
17045    ) -> Option<Task<Result<Navigated>>> {
17046        let selection = self.selections.newest::<usize>(&self.display_snapshot(cx));
17047        let multi_buffer = self.buffer.read(cx);
17048        let head = selection.head();
17049
17050        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
17051        let head_anchor = multi_buffer_snapshot.anchor_at(
17052            head,
17053            if head < selection.tail() {
17054                Bias::Right
17055            } else {
17056                Bias::Left
17057            },
17058        );
17059
17060        match self
17061            .find_all_references_task_sources
17062            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
17063        {
17064            Ok(_) => {
17065                log::info!(
17066                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
17067                );
17068                return None;
17069            }
17070            Err(i) => {
17071                self.find_all_references_task_sources.insert(i, head_anchor);
17072            }
17073        }
17074
17075        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
17076        let workspace = self.workspace()?;
17077        let project = workspace.read(cx).project().clone();
17078        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
17079        Some(cx.spawn_in(window, async move |editor, cx| {
17080            let _cleanup = cx.on_drop(&editor, move |editor, _| {
17081                if let Ok(i) = editor
17082                    .find_all_references_task_sources
17083                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
17084                {
17085                    editor.find_all_references_task_sources.remove(i);
17086                }
17087            });
17088
17089            let Some(locations) = references.await? else {
17090                return anyhow::Ok(Navigated::No);
17091            };
17092            let mut locations = cx.update(|_, cx| {
17093                locations
17094                    .into_iter()
17095                    .map(|location| {
17096                        let buffer = location.buffer.read(cx);
17097                        (location.buffer, location.range.to_point(buffer))
17098                    })
17099                    .into_group_map()
17100            })?;
17101            if locations.is_empty() {
17102                return anyhow::Ok(Navigated::No);
17103            }
17104            for ranges in locations.values_mut() {
17105                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
17106                ranges.dedup();
17107            }
17108
17109            workspace.update_in(cx, |workspace, window, cx| {
17110                let target = locations
17111                    .iter()
17112                    .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
17113                    .map(|(buffer, location)| {
17114                        buffer
17115                            .read(cx)
17116                            .text_for_range(location.clone())
17117                            .collect::<String>()
17118                    })
17119                    .filter(|text| !text.contains('\n'))
17120                    .unique()
17121                    .take(3)
17122                    .join(", ");
17123                let title = if target.is_empty() {
17124                    "References".to_owned()
17125                } else {
17126                    format!("References to {target}")
17127                };
17128                Self::open_locations_in_multibuffer(
17129                    workspace,
17130                    locations,
17131                    title,
17132                    false,
17133                    MultibufferSelectionMode::First,
17134                    window,
17135                    cx,
17136                );
17137                Navigated::Yes
17138            })
17139        }))
17140    }
17141
17142    /// Opens a multibuffer with the given project locations in it
17143    pub fn open_locations_in_multibuffer(
17144        workspace: &mut Workspace,
17145        locations: std::collections::HashMap<Entity<Buffer>, Vec<Range<Point>>>,
17146        title: String,
17147        split: bool,
17148        multibuffer_selection_mode: MultibufferSelectionMode,
17149        window: &mut Window,
17150        cx: &mut Context<Workspace>,
17151    ) {
17152        if locations.is_empty() {
17153            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
17154            return;
17155        }
17156
17157        let capability = workspace.project().read(cx).capability();
17158        let mut ranges = <Vec<Range<Anchor>>>::new();
17159
17160        // a key to find existing multibuffer editors with the same set of locations
17161        // to prevent us from opening more and more multibuffer tabs for searches and the like
17162        let mut key = (title.clone(), vec![]);
17163        let excerpt_buffer = cx.new(|cx| {
17164            let key = &mut key.1;
17165            let mut multibuffer = MultiBuffer::new(capability);
17166            for (buffer, mut ranges_for_buffer) in locations {
17167                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
17168                key.push((buffer.read(cx).remote_id(), ranges_for_buffer.clone()));
17169                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
17170                    PathKey::for_buffer(&buffer, cx),
17171                    buffer.clone(),
17172                    ranges_for_buffer,
17173                    multibuffer_context_lines(cx),
17174                    cx,
17175                );
17176                ranges.extend(new_ranges)
17177            }
17178
17179            multibuffer.with_title(title)
17180        });
17181        let existing = workspace.active_pane().update(cx, |pane, cx| {
17182            pane.items()
17183                .filter_map(|item| item.downcast::<Editor>())
17184                .find(|editor| {
17185                    editor
17186                        .read(cx)
17187                        .lookup_key
17188                        .as_ref()
17189                        .and_then(|it| {
17190                            it.downcast_ref::<(String, Vec<(BufferId, Vec<Range<Point>>)>)>()
17191                        })
17192                        .is_some_and(|it| *it == key)
17193                })
17194        });
17195        let editor = existing.unwrap_or_else(|| {
17196            cx.new(|cx| {
17197                let mut editor = Editor::for_multibuffer(
17198                    excerpt_buffer,
17199                    Some(workspace.project().clone()),
17200                    window,
17201                    cx,
17202                );
17203                editor.lookup_key = Some(Box::new(key));
17204                editor
17205            })
17206        });
17207        editor.update(cx, |editor, cx| match multibuffer_selection_mode {
17208            MultibufferSelectionMode::First => {
17209                if let Some(first_range) = ranges.first() {
17210                    editor.change_selections(
17211                        SelectionEffects::no_scroll(),
17212                        window,
17213                        cx,
17214                        |selections| {
17215                            selections.clear_disjoint();
17216                            selections.select_anchor_ranges(std::iter::once(first_range.clone()));
17217                        },
17218                    );
17219                }
17220                editor.highlight_background::<Self>(
17221                    &ranges,
17222                    |theme| theme.colors().editor_highlighted_line_background,
17223                    cx,
17224                );
17225            }
17226            MultibufferSelectionMode::All => {
17227                editor.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
17228                    selections.clear_disjoint();
17229                    selections.select_anchor_ranges(ranges);
17230                });
17231            }
17232        });
17233
17234        let item = Box::new(editor);
17235        let item_id = item.item_id();
17236
17237        if split {
17238            let pane = workspace.adjacent_pane(window, cx);
17239            workspace.add_item(pane, item, None, true, true, window, cx);
17240        } else if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
17241            let (preview_item_id, preview_item_idx) =
17242                workspace.active_pane().read_with(cx, |pane, _| {
17243                    (pane.preview_item_id(), pane.preview_item_idx())
17244                });
17245
17246            workspace.add_item_to_active_pane(item, preview_item_idx, true, window, cx);
17247
17248            if let Some(preview_item_id) = preview_item_id {
17249                workspace.active_pane().update(cx, |pane, cx| {
17250                    pane.remove_item(preview_item_id, false, false, window, cx);
17251                });
17252            }
17253        } else {
17254            workspace.add_item_to_active_pane(item, None, true, window, cx);
17255        }
17256        workspace.active_pane().update(cx, |pane, cx| {
17257            pane.set_preview_item_id(Some(item_id), cx);
17258        });
17259    }
17260
17261    pub fn rename(
17262        &mut self,
17263        _: &Rename,
17264        window: &mut Window,
17265        cx: &mut Context<Self>,
17266    ) -> Option<Task<Result<()>>> {
17267        use language::ToOffset as _;
17268
17269        let provider = self.semantics_provider.clone()?;
17270        let selection = self.selections.newest_anchor().clone();
17271        let (cursor_buffer, cursor_buffer_position) = self
17272            .buffer
17273            .read(cx)
17274            .text_anchor_for_position(selection.head(), cx)?;
17275        let (tail_buffer, cursor_buffer_position_end) = self
17276            .buffer
17277            .read(cx)
17278            .text_anchor_for_position(selection.tail(), cx)?;
17279        if tail_buffer != cursor_buffer {
17280            return None;
17281        }
17282
17283        let snapshot = cursor_buffer.read(cx).snapshot();
17284        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
17285        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
17286        let prepare_rename = provider
17287            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
17288            .unwrap_or_else(|| Task::ready(Ok(None)));
17289        drop(snapshot);
17290
17291        Some(cx.spawn_in(window, async move |this, cx| {
17292            let rename_range = if let Some(range) = prepare_rename.await? {
17293                Some(range)
17294            } else {
17295                this.update(cx, |this, cx| {
17296                    let buffer = this.buffer.read(cx).snapshot(cx);
17297                    let mut buffer_highlights = this
17298                        .document_highlights_for_position(selection.head(), &buffer)
17299                        .filter(|highlight| {
17300                            highlight.start.excerpt_id == selection.head().excerpt_id
17301                                && highlight.end.excerpt_id == selection.head().excerpt_id
17302                        });
17303                    buffer_highlights
17304                        .next()
17305                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
17306                })?
17307            };
17308            if let Some(rename_range) = rename_range {
17309                this.update_in(cx, |this, window, cx| {
17310                    let snapshot = cursor_buffer.read(cx).snapshot();
17311                    let rename_buffer_range = rename_range.to_offset(&snapshot);
17312                    let cursor_offset_in_rename_range =
17313                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
17314                    let cursor_offset_in_rename_range_end =
17315                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
17316
17317                    this.take_rename(false, window, cx);
17318                    let buffer = this.buffer.read(cx).read(cx);
17319                    let cursor_offset = selection.head().to_offset(&buffer);
17320                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
17321                    let rename_end = rename_start + rename_buffer_range.len();
17322                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
17323                    let mut old_highlight_id = None;
17324                    let old_name: Arc<str> = buffer
17325                        .chunks(rename_start..rename_end, true)
17326                        .map(|chunk| {
17327                            if old_highlight_id.is_none() {
17328                                old_highlight_id = chunk.syntax_highlight_id;
17329                            }
17330                            chunk.text
17331                        })
17332                        .collect::<String>()
17333                        .into();
17334
17335                    drop(buffer);
17336
17337                    // Position the selection in the rename editor so that it matches the current selection.
17338                    this.show_local_selections = false;
17339                    let rename_editor = cx.new(|cx| {
17340                        let mut editor = Editor::single_line(window, cx);
17341                        editor.buffer.update(cx, |buffer, cx| {
17342                            buffer.edit([(0..0, old_name.clone())], None, cx)
17343                        });
17344                        let rename_selection_range = match cursor_offset_in_rename_range
17345                            .cmp(&cursor_offset_in_rename_range_end)
17346                        {
17347                            Ordering::Equal => {
17348                                editor.select_all(&SelectAll, window, cx);
17349                                return editor;
17350                            }
17351                            Ordering::Less => {
17352                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
17353                            }
17354                            Ordering::Greater => {
17355                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
17356                            }
17357                        };
17358                        if rename_selection_range.end > old_name.len() {
17359                            editor.select_all(&SelectAll, window, cx);
17360                        } else {
17361                            editor.change_selections(Default::default(), window, cx, |s| {
17362                                s.select_ranges([rename_selection_range]);
17363                            });
17364                        }
17365                        editor
17366                    });
17367                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
17368                        if e == &EditorEvent::Focused {
17369                            cx.emit(EditorEvent::FocusedIn)
17370                        }
17371                    })
17372                    .detach();
17373
17374                    let write_highlights =
17375                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
17376                    let read_highlights =
17377                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
17378                    let ranges = write_highlights
17379                        .iter()
17380                        .flat_map(|(_, ranges)| ranges.iter())
17381                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
17382                        .cloned()
17383                        .collect();
17384
17385                    this.highlight_text::<Rename>(
17386                        ranges,
17387                        HighlightStyle {
17388                            fade_out: Some(0.6),
17389                            ..Default::default()
17390                        },
17391                        cx,
17392                    );
17393                    let rename_focus_handle = rename_editor.focus_handle(cx);
17394                    window.focus(&rename_focus_handle);
17395                    let block_id = this.insert_blocks(
17396                        [BlockProperties {
17397                            style: BlockStyle::Flex,
17398                            placement: BlockPlacement::Below(range.start),
17399                            height: Some(1),
17400                            render: Arc::new({
17401                                let rename_editor = rename_editor.clone();
17402                                move |cx: &mut BlockContext| {
17403                                    let mut text_style = cx.editor_style.text.clone();
17404                                    if let Some(highlight_style) = old_highlight_id
17405                                        .and_then(|h| h.style(&cx.editor_style.syntax))
17406                                    {
17407                                        text_style = text_style.highlight(highlight_style);
17408                                    }
17409                                    div()
17410                                        .block_mouse_except_scroll()
17411                                        .pl(cx.anchor_x)
17412                                        .child(EditorElement::new(
17413                                            &rename_editor,
17414                                            EditorStyle {
17415                                                background: cx.theme().system().transparent,
17416                                                local_player: cx.editor_style.local_player,
17417                                                text: text_style,
17418                                                scrollbar_width: cx.editor_style.scrollbar_width,
17419                                                syntax: cx.editor_style.syntax.clone(),
17420                                                status: cx.editor_style.status.clone(),
17421                                                inlay_hints_style: HighlightStyle {
17422                                                    font_weight: Some(FontWeight::BOLD),
17423                                                    ..make_inlay_hints_style(cx.app)
17424                                                },
17425                                                edit_prediction_styles: make_suggestion_styles(
17426                                                    cx.app,
17427                                                ),
17428                                                ..EditorStyle::default()
17429                                            },
17430                                        ))
17431                                        .into_any_element()
17432                                }
17433                            }),
17434                            priority: 0,
17435                        }],
17436                        Some(Autoscroll::fit()),
17437                        cx,
17438                    )[0];
17439                    this.pending_rename = Some(RenameState {
17440                        range,
17441                        old_name,
17442                        editor: rename_editor,
17443                        block_id,
17444                    });
17445                })?;
17446            }
17447
17448            Ok(())
17449        }))
17450    }
17451
17452    pub fn confirm_rename(
17453        &mut self,
17454        _: &ConfirmRename,
17455        window: &mut Window,
17456        cx: &mut Context<Self>,
17457    ) -> Option<Task<Result<()>>> {
17458        let rename = self.take_rename(false, window, cx)?;
17459        let workspace = self.workspace()?.downgrade();
17460        let (buffer, start) = self
17461            .buffer
17462            .read(cx)
17463            .text_anchor_for_position(rename.range.start, cx)?;
17464        let (end_buffer, _) = self
17465            .buffer
17466            .read(cx)
17467            .text_anchor_for_position(rename.range.end, cx)?;
17468        if buffer != end_buffer {
17469            return None;
17470        }
17471
17472        let old_name = rename.old_name;
17473        let new_name = rename.editor.read(cx).text(cx);
17474
17475        let rename = self.semantics_provider.as_ref()?.perform_rename(
17476            &buffer,
17477            start,
17478            new_name.clone(),
17479            cx,
17480        )?;
17481
17482        Some(cx.spawn_in(window, async move |editor, cx| {
17483            let project_transaction = rename.await?;
17484            Self::open_project_transaction(
17485                &editor,
17486                workspace,
17487                project_transaction,
17488                format!("Rename: {}{}", old_name, new_name),
17489                cx,
17490            )
17491            .await?;
17492
17493            editor.update(cx, |editor, cx| {
17494                editor.refresh_document_highlights(cx);
17495            })?;
17496            Ok(())
17497        }))
17498    }
17499
17500    fn take_rename(
17501        &mut self,
17502        moving_cursor: bool,
17503        window: &mut Window,
17504        cx: &mut Context<Self>,
17505    ) -> Option<RenameState> {
17506        let rename = self.pending_rename.take()?;
17507        if rename.editor.focus_handle(cx).is_focused(window) {
17508            window.focus(&self.focus_handle);
17509        }
17510
17511        self.remove_blocks(
17512            [rename.block_id].into_iter().collect(),
17513            Some(Autoscroll::fit()),
17514            cx,
17515        );
17516        self.clear_highlights::<Rename>(cx);
17517        self.show_local_selections = true;
17518
17519        if moving_cursor {
17520            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
17521                editor
17522                    .selections
17523                    .newest::<usize>(&editor.display_snapshot(cx))
17524                    .head()
17525            });
17526
17527            // Update the selection to match the position of the selection inside
17528            // the rename editor.
17529            let snapshot = self.buffer.read(cx).read(cx);
17530            let rename_range = rename.range.to_offset(&snapshot);
17531            let cursor_in_editor = snapshot
17532                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
17533                .min(rename_range.end);
17534            drop(snapshot);
17535
17536            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17537                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
17538            });
17539        } else {
17540            self.refresh_document_highlights(cx);
17541        }
17542
17543        Some(rename)
17544    }
17545
17546    pub fn pending_rename(&self) -> Option<&RenameState> {
17547        self.pending_rename.as_ref()
17548    }
17549
17550    fn format(
17551        &mut self,
17552        _: &Format,
17553        window: &mut Window,
17554        cx: &mut Context<Self>,
17555    ) -> Option<Task<Result<()>>> {
17556        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17557
17558        let project = match &self.project {
17559            Some(project) => project.clone(),
17560            None => return None,
17561        };
17562
17563        Some(self.perform_format(
17564            project,
17565            FormatTrigger::Manual,
17566            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
17567            window,
17568            cx,
17569        ))
17570    }
17571
17572    fn format_selections(
17573        &mut self,
17574        _: &FormatSelections,
17575        window: &mut Window,
17576        cx: &mut Context<Self>,
17577    ) -> Option<Task<Result<()>>> {
17578        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17579
17580        let project = match &self.project {
17581            Some(project) => project.clone(),
17582            None => return None,
17583        };
17584
17585        let ranges = self
17586            .selections
17587            .all_adjusted(&self.display_snapshot(cx))
17588            .into_iter()
17589            .map(|selection| selection.range())
17590            .collect_vec();
17591
17592        Some(self.perform_format(
17593            project,
17594            FormatTrigger::Manual,
17595            FormatTarget::Ranges(ranges),
17596            window,
17597            cx,
17598        ))
17599    }
17600
17601    fn perform_format(
17602        &mut self,
17603        project: Entity<Project>,
17604        trigger: FormatTrigger,
17605        target: FormatTarget,
17606        window: &mut Window,
17607        cx: &mut Context<Self>,
17608    ) -> Task<Result<()>> {
17609        let buffer = self.buffer.clone();
17610        let (buffers, target) = match target {
17611            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
17612            FormatTarget::Ranges(selection_ranges) => {
17613                let multi_buffer = buffer.read(cx);
17614                let snapshot = multi_buffer.read(cx);
17615                let mut buffers = HashSet::default();
17616                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
17617                    BTreeMap::new();
17618                for selection_range in selection_ranges {
17619                    for (buffer, buffer_range, _) in
17620                        snapshot.range_to_buffer_ranges(selection_range)
17621                    {
17622                        let buffer_id = buffer.remote_id();
17623                        let start = buffer.anchor_before(buffer_range.start);
17624                        let end = buffer.anchor_after(buffer_range.end);
17625                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
17626                        buffer_id_to_ranges
17627                            .entry(buffer_id)
17628                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
17629                            .or_insert_with(|| vec![start..end]);
17630                    }
17631                }
17632                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
17633            }
17634        };
17635
17636        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
17637        let selections_prev = transaction_id_prev
17638            .and_then(|transaction_id_prev| {
17639                // default to selections as they were after the last edit, if we have them,
17640                // instead of how they are now.
17641                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
17642                // will take you back to where you made the last edit, instead of staying where you scrolled
17643                self.selection_history
17644                    .transaction(transaction_id_prev)
17645                    .map(|t| t.0.clone())
17646            })
17647            .unwrap_or_else(|| self.selections.disjoint_anchors_arc());
17648
17649        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
17650        let format = project.update(cx, |project, cx| {
17651            project.format(buffers, target, true, trigger, cx)
17652        });
17653
17654        cx.spawn_in(window, async move |editor, cx| {
17655            let transaction = futures::select_biased! {
17656                transaction = format.log_err().fuse() => transaction,
17657                () = timeout => {
17658                    log::warn!("timed out waiting for formatting");
17659                    None
17660                }
17661            };
17662
17663            buffer
17664                .update(cx, |buffer, cx| {
17665                    if let Some(transaction) = transaction
17666                        && !buffer.is_singleton()
17667                    {
17668                        buffer.push_transaction(&transaction.0, cx);
17669                    }
17670                    cx.notify();
17671                })
17672                .ok();
17673
17674            if let Some(transaction_id_now) =
17675                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
17676            {
17677                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
17678                if has_new_transaction {
17679                    _ = editor.update(cx, |editor, _| {
17680                        editor
17681                            .selection_history
17682                            .insert_transaction(transaction_id_now, selections_prev);
17683                    });
17684                }
17685            }
17686
17687            Ok(())
17688        })
17689    }
17690
17691    fn organize_imports(
17692        &mut self,
17693        _: &OrganizeImports,
17694        window: &mut Window,
17695        cx: &mut Context<Self>,
17696    ) -> Option<Task<Result<()>>> {
17697        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17698        let project = match &self.project {
17699            Some(project) => project.clone(),
17700            None => return None,
17701        };
17702        Some(self.perform_code_action_kind(
17703            project,
17704            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
17705            window,
17706            cx,
17707        ))
17708    }
17709
17710    fn perform_code_action_kind(
17711        &mut self,
17712        project: Entity<Project>,
17713        kind: CodeActionKind,
17714        window: &mut Window,
17715        cx: &mut Context<Self>,
17716    ) -> Task<Result<()>> {
17717        let buffer = self.buffer.clone();
17718        let buffers = buffer.read(cx).all_buffers();
17719        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
17720        let apply_action = project.update(cx, |project, cx| {
17721            project.apply_code_action_kind(buffers, kind, true, cx)
17722        });
17723        cx.spawn_in(window, async move |_, cx| {
17724            let transaction = futures::select_biased! {
17725                () = timeout => {
17726                    log::warn!("timed out waiting for executing code action");
17727                    None
17728                }
17729                transaction = apply_action.log_err().fuse() => transaction,
17730            };
17731            buffer
17732                .update(cx, |buffer, cx| {
17733                    // check if we need this
17734                    if let Some(transaction) = transaction
17735                        && !buffer.is_singleton()
17736                    {
17737                        buffer.push_transaction(&transaction.0, cx);
17738                    }
17739                    cx.notify();
17740                })
17741                .ok();
17742            Ok(())
17743        })
17744    }
17745
17746    pub fn restart_language_server(
17747        &mut self,
17748        _: &RestartLanguageServer,
17749        _: &mut Window,
17750        cx: &mut Context<Self>,
17751    ) {
17752        if let Some(project) = self.project.clone() {
17753            self.buffer.update(cx, |multi_buffer, cx| {
17754                project.update(cx, |project, cx| {
17755                    project.restart_language_servers_for_buffers(
17756                        multi_buffer.all_buffers().into_iter().collect(),
17757                        HashSet::default(),
17758                        cx,
17759                    );
17760                });
17761            })
17762        }
17763    }
17764
17765    pub fn stop_language_server(
17766        &mut self,
17767        _: &StopLanguageServer,
17768        _: &mut Window,
17769        cx: &mut Context<Self>,
17770    ) {
17771        if let Some(project) = self.project.clone() {
17772            self.buffer.update(cx, |multi_buffer, cx| {
17773                project.update(cx, |project, cx| {
17774                    project.stop_language_servers_for_buffers(
17775                        multi_buffer.all_buffers().into_iter().collect(),
17776                        HashSet::default(),
17777                        cx,
17778                    );
17779                });
17780            });
17781            self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
17782        }
17783    }
17784
17785    fn cancel_language_server_work(
17786        workspace: &mut Workspace,
17787        _: &actions::CancelLanguageServerWork,
17788        _: &mut Window,
17789        cx: &mut Context<Workspace>,
17790    ) {
17791        let project = workspace.project();
17792        let buffers = workspace
17793            .active_item(cx)
17794            .and_then(|item| item.act_as::<Editor>(cx))
17795            .map_or(HashSet::default(), |editor| {
17796                editor.read(cx).buffer.read(cx).all_buffers()
17797            });
17798        project.update(cx, |project, cx| {
17799            project.cancel_language_server_work_for_buffers(buffers, cx);
17800        });
17801    }
17802
17803    fn show_character_palette(
17804        &mut self,
17805        _: &ShowCharacterPalette,
17806        window: &mut Window,
17807        _: &mut Context<Self>,
17808    ) {
17809        window.show_character_palette();
17810    }
17811
17812    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
17813        if !self.diagnostics_enabled() {
17814            return;
17815        }
17816
17817        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
17818            let buffer = self.buffer.read(cx).snapshot(cx);
17819            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
17820            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
17821            let is_valid = buffer
17822                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
17823                .any(|entry| {
17824                    entry.diagnostic.is_primary
17825                        && !entry.range.is_empty()
17826                        && entry.range.start == primary_range_start
17827                        && entry.diagnostic.message == active_diagnostics.active_message
17828                });
17829
17830            if !is_valid {
17831                self.dismiss_diagnostics(cx);
17832            }
17833        }
17834    }
17835
17836    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
17837        match &self.active_diagnostics {
17838            ActiveDiagnostic::Group(group) => Some(group),
17839            _ => None,
17840        }
17841    }
17842
17843    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
17844        if !self.diagnostics_enabled() {
17845            return;
17846        }
17847        self.dismiss_diagnostics(cx);
17848        self.active_diagnostics = ActiveDiagnostic::All;
17849    }
17850
17851    fn activate_diagnostics(
17852        &mut self,
17853        buffer_id: BufferId,
17854        diagnostic: DiagnosticEntryRef<'_, usize>,
17855        window: &mut Window,
17856        cx: &mut Context<Self>,
17857    ) {
17858        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
17859            return;
17860        }
17861        self.dismiss_diagnostics(cx);
17862        let snapshot = self.snapshot(window, cx);
17863        let buffer = self.buffer.read(cx).snapshot(cx);
17864        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
17865            return;
17866        };
17867
17868        let diagnostic_group = buffer
17869            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
17870            .collect::<Vec<_>>();
17871
17872        let blocks =
17873            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
17874
17875        let blocks = self.display_map.update(cx, |display_map, cx| {
17876            display_map.insert_blocks(blocks, cx).into_iter().collect()
17877        });
17878        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
17879            active_range: buffer.anchor_before(diagnostic.range.start)
17880                ..buffer.anchor_after(diagnostic.range.end),
17881            active_message: diagnostic.diagnostic.message.clone(),
17882            group_id: diagnostic.diagnostic.group_id,
17883            blocks,
17884        });
17885        cx.notify();
17886    }
17887
17888    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
17889        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
17890            return;
17891        };
17892
17893        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
17894        if let ActiveDiagnostic::Group(group) = prev {
17895            self.display_map.update(cx, |display_map, cx| {
17896                display_map.remove_blocks(group.blocks, cx);
17897            });
17898            cx.notify();
17899        }
17900    }
17901
17902    /// Disable inline diagnostics rendering for this editor.
17903    pub fn disable_inline_diagnostics(&mut self) {
17904        self.inline_diagnostics_enabled = false;
17905        self.inline_diagnostics_update = Task::ready(());
17906        self.inline_diagnostics.clear();
17907    }
17908
17909    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
17910        self.diagnostics_enabled = false;
17911        self.dismiss_diagnostics(cx);
17912        self.inline_diagnostics_update = Task::ready(());
17913        self.inline_diagnostics.clear();
17914    }
17915
17916    pub fn disable_word_completions(&mut self) {
17917        self.word_completions_enabled = false;
17918    }
17919
17920    pub fn diagnostics_enabled(&self) -> bool {
17921        self.diagnostics_enabled && self.mode.is_full()
17922    }
17923
17924    pub fn inline_diagnostics_enabled(&self) -> bool {
17925        self.inline_diagnostics_enabled && self.diagnostics_enabled()
17926    }
17927
17928    pub fn show_inline_diagnostics(&self) -> bool {
17929        self.show_inline_diagnostics
17930    }
17931
17932    pub fn toggle_inline_diagnostics(
17933        &mut self,
17934        _: &ToggleInlineDiagnostics,
17935        window: &mut Window,
17936        cx: &mut Context<Editor>,
17937    ) {
17938        self.show_inline_diagnostics = !self.show_inline_diagnostics;
17939        self.refresh_inline_diagnostics(false, window, cx);
17940    }
17941
17942    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
17943        self.diagnostics_max_severity = severity;
17944        self.display_map.update(cx, |display_map, _| {
17945            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
17946        });
17947    }
17948
17949    pub fn toggle_diagnostics(
17950        &mut self,
17951        _: &ToggleDiagnostics,
17952        window: &mut Window,
17953        cx: &mut Context<Editor>,
17954    ) {
17955        if !self.diagnostics_enabled() {
17956            return;
17957        }
17958
17959        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
17960            EditorSettings::get_global(cx)
17961                .diagnostics_max_severity
17962                .filter(|severity| severity != &DiagnosticSeverity::Off)
17963                .unwrap_or(DiagnosticSeverity::Hint)
17964        } else {
17965            DiagnosticSeverity::Off
17966        };
17967        self.set_max_diagnostics_severity(new_severity, cx);
17968        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
17969            self.active_diagnostics = ActiveDiagnostic::None;
17970            self.inline_diagnostics_update = Task::ready(());
17971            self.inline_diagnostics.clear();
17972        } else {
17973            self.refresh_inline_diagnostics(false, window, cx);
17974        }
17975
17976        cx.notify();
17977    }
17978
17979    pub fn toggle_minimap(
17980        &mut self,
17981        _: &ToggleMinimap,
17982        window: &mut Window,
17983        cx: &mut Context<Editor>,
17984    ) {
17985        if self.supports_minimap(cx) {
17986            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
17987        }
17988    }
17989
17990    fn refresh_inline_diagnostics(
17991        &mut self,
17992        debounce: bool,
17993        window: &mut Window,
17994        cx: &mut Context<Self>,
17995    ) {
17996        let max_severity = ProjectSettings::get_global(cx)
17997            .diagnostics
17998            .inline
17999            .max_severity
18000            .unwrap_or(self.diagnostics_max_severity);
18001
18002        if !self.inline_diagnostics_enabled()
18003            || !self.diagnostics_enabled()
18004            || !self.show_inline_diagnostics
18005            || max_severity == DiagnosticSeverity::Off
18006        {
18007            self.inline_diagnostics_update = Task::ready(());
18008            self.inline_diagnostics.clear();
18009            return;
18010        }
18011
18012        let debounce_ms = ProjectSettings::get_global(cx)
18013            .diagnostics
18014            .inline
18015            .update_debounce_ms;
18016        let debounce = if debounce && debounce_ms > 0 {
18017            Some(Duration::from_millis(debounce_ms))
18018        } else {
18019            None
18020        };
18021        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
18022            if let Some(debounce) = debounce {
18023                cx.background_executor().timer(debounce).await;
18024            }
18025            let Some(snapshot) = editor.upgrade().and_then(|editor| {
18026                editor
18027                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
18028                    .ok()
18029            }) else {
18030                return;
18031            };
18032
18033            let new_inline_diagnostics = cx
18034                .background_spawn(async move {
18035                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
18036                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
18037                        let message = diagnostic_entry
18038                            .diagnostic
18039                            .message
18040                            .split_once('\n')
18041                            .map(|(line, _)| line)
18042                            .map(SharedString::new)
18043                            .unwrap_or_else(|| {
18044                                SharedString::new(&*diagnostic_entry.diagnostic.message)
18045                            });
18046                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
18047                        let (Ok(i) | Err(i)) = inline_diagnostics
18048                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
18049                        inline_diagnostics.insert(
18050                            i,
18051                            (
18052                                start_anchor,
18053                                InlineDiagnostic {
18054                                    message,
18055                                    group_id: diagnostic_entry.diagnostic.group_id,
18056                                    start: diagnostic_entry.range.start.to_point(&snapshot),
18057                                    is_primary: diagnostic_entry.diagnostic.is_primary,
18058                                    severity: diagnostic_entry.diagnostic.severity,
18059                                },
18060                            ),
18061                        );
18062                    }
18063                    inline_diagnostics
18064                })
18065                .await;
18066
18067            editor
18068                .update(cx, |editor, cx| {
18069                    editor.inline_diagnostics = new_inline_diagnostics;
18070                    cx.notify();
18071                })
18072                .ok();
18073        });
18074    }
18075
18076    fn pull_diagnostics(
18077        &mut self,
18078        buffer_id: Option<BufferId>,
18079        window: &Window,
18080        cx: &mut Context<Self>,
18081    ) -> Option<()> {
18082        if self.ignore_lsp_data() || !self.diagnostics_enabled() {
18083            return None;
18084        }
18085        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
18086            .diagnostics
18087            .lsp_pull_diagnostics;
18088        if !pull_diagnostics_settings.enabled {
18089            return None;
18090        }
18091        let project = self.project()?.downgrade();
18092        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
18093        let mut buffers = self.buffer.read(cx).all_buffers();
18094        buffers.retain(|buffer| {
18095            let buffer_id_to_retain = buffer.read(cx).remote_id();
18096            buffer_id.is_none_or(|buffer_id| buffer_id == buffer_id_to_retain)
18097                && self.registered_buffers.contains_key(&buffer_id_to_retain)
18098        });
18099        if buffers.is_empty() {
18100            self.pull_diagnostics_task = Task::ready(());
18101            return None;
18102        }
18103
18104        self.pull_diagnostics_task = cx.spawn_in(window, async move |editor, cx| {
18105            cx.background_executor().timer(debounce).await;
18106
18107            let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
18108                buffers
18109                    .into_iter()
18110                    .filter_map(|buffer| {
18111                        project
18112                            .update(cx, |project, cx| {
18113                                project.lsp_store().update(cx, |lsp_store, cx| {
18114                                    lsp_store.pull_diagnostics_for_buffer(buffer, cx)
18115                                })
18116                            })
18117                            .ok()
18118                    })
18119                    .collect::<FuturesUnordered<_>>()
18120            }) else {
18121                return;
18122            };
18123
18124            while let Some(pull_task) = pull_diagnostics_tasks.next().await {
18125                match pull_task {
18126                    Ok(()) => {
18127                        if editor
18128                            .update_in(cx, |editor, window, cx| {
18129                                editor.update_diagnostics_state(window, cx);
18130                            })
18131                            .is_err()
18132                        {
18133                            return;
18134                        }
18135                    }
18136                    Err(e) => log::error!("Failed to update project diagnostics: {e:#}"),
18137                }
18138            }
18139        });
18140
18141        Some(())
18142    }
18143
18144    pub fn set_selections_from_remote(
18145        &mut self,
18146        selections: Vec<Selection<Anchor>>,
18147        pending_selection: Option<Selection<Anchor>>,
18148        window: &mut Window,
18149        cx: &mut Context<Self>,
18150    ) {
18151        let old_cursor_position = self.selections.newest_anchor().head();
18152        self.selections
18153            .change_with(&self.display_snapshot(cx), |s| {
18154                s.select_anchors(selections);
18155                if let Some(pending_selection) = pending_selection {
18156                    s.set_pending(pending_selection, SelectMode::Character);
18157                } else {
18158                    s.clear_pending();
18159                }
18160            });
18161        self.selections_did_change(
18162            false,
18163            &old_cursor_position,
18164            SelectionEffects::default(),
18165            window,
18166            cx,
18167        );
18168    }
18169
18170    pub fn transact(
18171        &mut self,
18172        window: &mut Window,
18173        cx: &mut Context<Self>,
18174        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
18175    ) -> Option<TransactionId> {
18176        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
18177            this.start_transaction_at(Instant::now(), window, cx);
18178            update(this, window, cx);
18179            this.end_transaction_at(Instant::now(), cx)
18180        })
18181    }
18182
18183    pub fn start_transaction_at(
18184        &mut self,
18185        now: Instant,
18186        window: &mut Window,
18187        cx: &mut Context<Self>,
18188    ) -> Option<TransactionId> {
18189        self.end_selection(window, cx);
18190        if let Some(tx_id) = self
18191            .buffer
18192            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
18193        {
18194            self.selection_history
18195                .insert_transaction(tx_id, self.selections.disjoint_anchors_arc());
18196            cx.emit(EditorEvent::TransactionBegun {
18197                transaction_id: tx_id,
18198            });
18199            Some(tx_id)
18200        } else {
18201            None
18202        }
18203    }
18204
18205    pub fn end_transaction_at(
18206        &mut self,
18207        now: Instant,
18208        cx: &mut Context<Self>,
18209    ) -> Option<TransactionId> {
18210        if let Some(transaction_id) = self
18211            .buffer
18212            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
18213        {
18214            if let Some((_, end_selections)) =
18215                self.selection_history.transaction_mut(transaction_id)
18216            {
18217                *end_selections = Some(self.selections.disjoint_anchors_arc());
18218            } else {
18219                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
18220            }
18221
18222            cx.emit(EditorEvent::Edited { transaction_id });
18223            Some(transaction_id)
18224        } else {
18225            None
18226        }
18227    }
18228
18229    pub fn modify_transaction_selection_history(
18230        &mut self,
18231        transaction_id: TransactionId,
18232        modify: impl FnOnce(&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)),
18233    ) -> bool {
18234        self.selection_history
18235            .transaction_mut(transaction_id)
18236            .map(modify)
18237            .is_some()
18238    }
18239
18240    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
18241        if self.selection_mark_mode {
18242            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
18243                s.move_with(|_, sel| {
18244                    sel.collapse_to(sel.head(), SelectionGoal::None);
18245                });
18246            })
18247        }
18248        self.selection_mark_mode = true;
18249        cx.notify();
18250    }
18251
18252    pub fn swap_selection_ends(
18253        &mut self,
18254        _: &actions::SwapSelectionEnds,
18255        window: &mut Window,
18256        cx: &mut Context<Self>,
18257    ) {
18258        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
18259            s.move_with(|_, sel| {
18260                if sel.start != sel.end {
18261                    sel.reversed = !sel.reversed
18262                }
18263            });
18264        });
18265        self.request_autoscroll(Autoscroll::newest(), cx);
18266        cx.notify();
18267    }
18268
18269    pub fn toggle_focus(
18270        workspace: &mut Workspace,
18271        _: &actions::ToggleFocus,
18272        window: &mut Window,
18273        cx: &mut Context<Workspace>,
18274    ) {
18275        let Some(item) = workspace.recent_active_item_by_type::<Self>(cx) else {
18276            return;
18277        };
18278        workspace.activate_item(&item, true, true, window, cx);
18279    }
18280
18281    pub fn toggle_fold(
18282        &mut self,
18283        _: &actions::ToggleFold,
18284        window: &mut Window,
18285        cx: &mut Context<Self>,
18286    ) {
18287        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18288            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18289            let selection = self.selections.newest::<Point>(&display_map);
18290
18291            let range = if selection.is_empty() {
18292                let point = selection.head().to_display_point(&display_map);
18293                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
18294                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
18295                    .to_point(&display_map);
18296                start..end
18297            } else {
18298                selection.range()
18299            };
18300            if display_map.folds_in_range(range).next().is_some() {
18301                self.unfold_lines(&Default::default(), window, cx)
18302            } else {
18303                self.fold(&Default::default(), window, cx)
18304            }
18305        } else {
18306            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18307            let buffer_ids: HashSet<_> = self
18308                .selections
18309                .disjoint_anchor_ranges()
18310                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18311                .collect();
18312
18313            let should_unfold = buffer_ids
18314                .iter()
18315                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
18316
18317            for buffer_id in buffer_ids {
18318                if should_unfold {
18319                    self.unfold_buffer(buffer_id, cx);
18320                } else {
18321                    self.fold_buffer(buffer_id, cx);
18322                }
18323            }
18324        }
18325    }
18326
18327    pub fn toggle_fold_recursive(
18328        &mut self,
18329        _: &actions::ToggleFoldRecursive,
18330        window: &mut Window,
18331        cx: &mut Context<Self>,
18332    ) {
18333        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
18334
18335        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18336        let range = if selection.is_empty() {
18337            let point = selection.head().to_display_point(&display_map);
18338            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
18339            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
18340                .to_point(&display_map);
18341            start..end
18342        } else {
18343            selection.range()
18344        };
18345        if display_map.folds_in_range(range).next().is_some() {
18346            self.unfold_recursive(&Default::default(), window, cx)
18347        } else {
18348            self.fold_recursive(&Default::default(), window, cx)
18349        }
18350    }
18351
18352    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
18353        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18354            let mut to_fold = Vec::new();
18355            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18356            let selections = self.selections.all_adjusted(&display_map);
18357
18358            for selection in selections {
18359                let range = selection.range().sorted();
18360                let buffer_start_row = range.start.row;
18361
18362                if range.start.row != range.end.row {
18363                    let mut found = false;
18364                    let mut row = range.start.row;
18365                    while row <= range.end.row {
18366                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
18367                        {
18368                            found = true;
18369                            row = crease.range().end.row + 1;
18370                            to_fold.push(crease);
18371                        } else {
18372                            row += 1
18373                        }
18374                    }
18375                    if found {
18376                        continue;
18377                    }
18378                }
18379
18380                for row in (0..=range.start.row).rev() {
18381                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
18382                        && crease.range().end.row >= buffer_start_row
18383                    {
18384                        to_fold.push(crease);
18385                        if row <= range.start.row {
18386                            break;
18387                        }
18388                    }
18389                }
18390            }
18391
18392            self.fold_creases(to_fold, true, window, cx);
18393        } else {
18394            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18395            let buffer_ids = self
18396                .selections
18397                .disjoint_anchor_ranges()
18398                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18399                .collect::<HashSet<_>>();
18400            for buffer_id in buffer_ids {
18401                self.fold_buffer(buffer_id, cx);
18402            }
18403        }
18404    }
18405
18406    pub fn toggle_fold_all(
18407        &mut self,
18408        _: &actions::ToggleFoldAll,
18409        window: &mut Window,
18410        cx: &mut Context<Self>,
18411    ) {
18412        if self.buffer.read(cx).is_singleton() {
18413            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18414            let has_folds = display_map
18415                .folds_in_range(0..display_map.buffer_snapshot().len())
18416                .next()
18417                .is_some();
18418
18419            if has_folds {
18420                self.unfold_all(&actions::UnfoldAll, window, cx);
18421            } else {
18422                self.fold_all(&actions::FoldAll, window, cx);
18423            }
18424        } else {
18425            let buffer_ids = self.buffer.read(cx).excerpt_buffer_ids();
18426            let should_unfold = buffer_ids
18427                .iter()
18428                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
18429
18430            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
18431                editor
18432                    .update_in(cx, |editor, _, cx| {
18433                        for buffer_id in buffer_ids {
18434                            if should_unfold {
18435                                editor.unfold_buffer(buffer_id, cx);
18436                            } else {
18437                                editor.fold_buffer(buffer_id, cx);
18438                            }
18439                        }
18440                    })
18441                    .ok();
18442            });
18443        }
18444    }
18445
18446    fn fold_at_level(
18447        &mut self,
18448        fold_at: &FoldAtLevel,
18449        window: &mut Window,
18450        cx: &mut Context<Self>,
18451    ) {
18452        if !self.buffer.read(cx).is_singleton() {
18453            return;
18454        }
18455
18456        let fold_at_level = fold_at.0;
18457        let snapshot = self.buffer.read(cx).snapshot(cx);
18458        let mut to_fold = Vec::new();
18459        let mut stack = vec![(0, snapshot.max_row().0, 1)];
18460
18461        let row_ranges_to_keep: Vec<Range<u32>> = self
18462            .selections
18463            .all::<Point>(&self.display_snapshot(cx))
18464            .into_iter()
18465            .map(|sel| sel.start.row..sel.end.row)
18466            .collect();
18467
18468        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
18469            while start_row < end_row {
18470                match self
18471                    .snapshot(window, cx)
18472                    .crease_for_buffer_row(MultiBufferRow(start_row))
18473                {
18474                    Some(crease) => {
18475                        let nested_start_row = crease.range().start.row + 1;
18476                        let nested_end_row = crease.range().end.row;
18477
18478                        if current_level < fold_at_level {
18479                            stack.push((nested_start_row, nested_end_row, current_level + 1));
18480                        } else if current_level == fold_at_level {
18481                            // Fold iff there is no selection completely contained within the fold region
18482                            if !row_ranges_to_keep.iter().any(|selection| {
18483                                selection.end >= nested_start_row
18484                                    && selection.start <= nested_end_row
18485                            }) {
18486                                to_fold.push(crease);
18487                            }
18488                        }
18489
18490                        start_row = nested_end_row + 1;
18491                    }
18492                    None => start_row += 1,
18493                }
18494            }
18495        }
18496
18497        self.fold_creases(to_fold, true, window, cx);
18498    }
18499
18500    pub fn fold_at_level_1(
18501        &mut self,
18502        _: &actions::FoldAtLevel1,
18503        window: &mut Window,
18504        cx: &mut Context<Self>,
18505    ) {
18506        self.fold_at_level(&actions::FoldAtLevel(1), window, cx);
18507    }
18508
18509    pub fn fold_at_level_2(
18510        &mut self,
18511        _: &actions::FoldAtLevel2,
18512        window: &mut Window,
18513        cx: &mut Context<Self>,
18514    ) {
18515        self.fold_at_level(&actions::FoldAtLevel(2), window, cx);
18516    }
18517
18518    pub fn fold_at_level_3(
18519        &mut self,
18520        _: &actions::FoldAtLevel3,
18521        window: &mut Window,
18522        cx: &mut Context<Self>,
18523    ) {
18524        self.fold_at_level(&actions::FoldAtLevel(3), window, cx);
18525    }
18526
18527    pub fn fold_at_level_4(
18528        &mut self,
18529        _: &actions::FoldAtLevel4,
18530        window: &mut Window,
18531        cx: &mut Context<Self>,
18532    ) {
18533        self.fold_at_level(&actions::FoldAtLevel(4), window, cx);
18534    }
18535
18536    pub fn fold_at_level_5(
18537        &mut self,
18538        _: &actions::FoldAtLevel5,
18539        window: &mut Window,
18540        cx: &mut Context<Self>,
18541    ) {
18542        self.fold_at_level(&actions::FoldAtLevel(5), window, cx);
18543    }
18544
18545    pub fn fold_at_level_6(
18546        &mut self,
18547        _: &actions::FoldAtLevel6,
18548        window: &mut Window,
18549        cx: &mut Context<Self>,
18550    ) {
18551        self.fold_at_level(&actions::FoldAtLevel(6), window, cx);
18552    }
18553
18554    pub fn fold_at_level_7(
18555        &mut self,
18556        _: &actions::FoldAtLevel7,
18557        window: &mut Window,
18558        cx: &mut Context<Self>,
18559    ) {
18560        self.fold_at_level(&actions::FoldAtLevel(7), window, cx);
18561    }
18562
18563    pub fn fold_at_level_8(
18564        &mut self,
18565        _: &actions::FoldAtLevel8,
18566        window: &mut Window,
18567        cx: &mut Context<Self>,
18568    ) {
18569        self.fold_at_level(&actions::FoldAtLevel(8), window, cx);
18570    }
18571
18572    pub fn fold_at_level_9(
18573        &mut self,
18574        _: &actions::FoldAtLevel9,
18575        window: &mut Window,
18576        cx: &mut Context<Self>,
18577    ) {
18578        self.fold_at_level(&actions::FoldAtLevel(9), window, cx);
18579    }
18580
18581    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
18582        if self.buffer.read(cx).is_singleton() {
18583            let mut fold_ranges = Vec::new();
18584            let snapshot = self.buffer.read(cx).snapshot(cx);
18585
18586            for row in 0..snapshot.max_row().0 {
18587                if let Some(foldable_range) = self
18588                    .snapshot(window, cx)
18589                    .crease_for_buffer_row(MultiBufferRow(row))
18590                {
18591                    fold_ranges.push(foldable_range);
18592                }
18593            }
18594
18595            self.fold_creases(fold_ranges, true, window, cx);
18596        } else {
18597            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
18598                editor
18599                    .update_in(cx, |editor, _, cx| {
18600                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
18601                            editor.fold_buffer(buffer_id, cx);
18602                        }
18603                    })
18604                    .ok();
18605            });
18606        }
18607    }
18608
18609    pub fn fold_function_bodies(
18610        &mut self,
18611        _: &actions::FoldFunctionBodies,
18612        window: &mut Window,
18613        cx: &mut Context<Self>,
18614    ) {
18615        let snapshot = self.buffer.read(cx).snapshot(cx);
18616
18617        let ranges = snapshot
18618            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
18619            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
18620            .collect::<Vec<_>>();
18621
18622        let creases = ranges
18623            .into_iter()
18624            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
18625            .collect();
18626
18627        self.fold_creases(creases, true, window, cx);
18628    }
18629
18630    pub fn fold_recursive(
18631        &mut self,
18632        _: &actions::FoldRecursive,
18633        window: &mut Window,
18634        cx: &mut Context<Self>,
18635    ) {
18636        let mut to_fold = Vec::new();
18637        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18638        let selections = self.selections.all_adjusted(&display_map);
18639
18640        for selection in selections {
18641            let range = selection.range().sorted();
18642            let buffer_start_row = range.start.row;
18643
18644            if range.start.row != range.end.row {
18645                let mut found = false;
18646                for row in range.start.row..=range.end.row {
18647                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
18648                        found = true;
18649                        to_fold.push(crease);
18650                    }
18651                }
18652                if found {
18653                    continue;
18654                }
18655            }
18656
18657            for row in (0..=range.start.row).rev() {
18658                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
18659                    if crease.range().end.row >= buffer_start_row {
18660                        to_fold.push(crease);
18661                    } else {
18662                        break;
18663                    }
18664                }
18665            }
18666        }
18667
18668        self.fold_creases(to_fold, true, window, cx);
18669    }
18670
18671    pub fn fold_at(
18672        &mut self,
18673        buffer_row: MultiBufferRow,
18674        window: &mut Window,
18675        cx: &mut Context<Self>,
18676    ) {
18677        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18678
18679        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
18680            let autoscroll = self
18681                .selections
18682                .all::<Point>(&display_map)
18683                .iter()
18684                .any(|selection| crease.range().overlaps(&selection.range()));
18685
18686            self.fold_creases(vec![crease], autoscroll, window, cx);
18687        }
18688    }
18689
18690    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
18691        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18692            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18693            let buffer = display_map.buffer_snapshot();
18694            let selections = self.selections.all::<Point>(&display_map);
18695            let ranges = selections
18696                .iter()
18697                .map(|s| {
18698                    let range = s.display_range(&display_map).sorted();
18699                    let mut start = range.start.to_point(&display_map);
18700                    let mut end = range.end.to_point(&display_map);
18701                    start.column = 0;
18702                    end.column = buffer.line_len(MultiBufferRow(end.row));
18703                    start..end
18704                })
18705                .collect::<Vec<_>>();
18706
18707            self.unfold_ranges(&ranges, true, true, cx);
18708        } else {
18709            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18710            let buffer_ids = self
18711                .selections
18712                .disjoint_anchor_ranges()
18713                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18714                .collect::<HashSet<_>>();
18715            for buffer_id in buffer_ids {
18716                self.unfold_buffer(buffer_id, cx);
18717            }
18718        }
18719    }
18720
18721    pub fn unfold_recursive(
18722        &mut self,
18723        _: &UnfoldRecursive,
18724        _window: &mut Window,
18725        cx: &mut Context<Self>,
18726    ) {
18727        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18728        let selections = self.selections.all::<Point>(&display_map);
18729        let ranges = selections
18730            .iter()
18731            .map(|s| {
18732                let mut range = s.display_range(&display_map).sorted();
18733                *range.start.column_mut() = 0;
18734                *range.end.column_mut() = display_map.line_len(range.end.row());
18735                let start = range.start.to_point(&display_map);
18736                let end = range.end.to_point(&display_map);
18737                start..end
18738            })
18739            .collect::<Vec<_>>();
18740
18741        self.unfold_ranges(&ranges, true, true, cx);
18742    }
18743
18744    pub fn unfold_at(
18745        &mut self,
18746        buffer_row: MultiBufferRow,
18747        _window: &mut Window,
18748        cx: &mut Context<Self>,
18749    ) {
18750        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18751
18752        let intersection_range = Point::new(buffer_row.0, 0)
18753            ..Point::new(
18754                buffer_row.0,
18755                display_map.buffer_snapshot().line_len(buffer_row),
18756            );
18757
18758        let autoscroll = self
18759            .selections
18760            .all::<Point>(&display_map)
18761            .iter()
18762            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
18763
18764        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
18765    }
18766
18767    pub fn unfold_all(
18768        &mut self,
18769        _: &actions::UnfoldAll,
18770        _window: &mut Window,
18771        cx: &mut Context<Self>,
18772    ) {
18773        if self.buffer.read(cx).is_singleton() {
18774            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18775            self.unfold_ranges(&[0..display_map.buffer_snapshot().len()], true, true, cx);
18776        } else {
18777            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
18778                editor
18779                    .update(cx, |editor, cx| {
18780                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
18781                            editor.unfold_buffer(buffer_id, cx);
18782                        }
18783                    })
18784                    .ok();
18785            });
18786        }
18787    }
18788
18789    pub fn fold_selected_ranges(
18790        &mut self,
18791        _: &FoldSelectedRanges,
18792        window: &mut Window,
18793        cx: &mut Context<Self>,
18794    ) {
18795        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18796        let selections = self.selections.all_adjusted(&display_map);
18797        let ranges = selections
18798            .into_iter()
18799            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
18800            .collect::<Vec<_>>();
18801        self.fold_creases(ranges, true, window, cx);
18802    }
18803
18804    pub fn fold_ranges<T: ToOffset + Clone>(
18805        &mut self,
18806        ranges: Vec<Range<T>>,
18807        auto_scroll: bool,
18808        window: &mut Window,
18809        cx: &mut Context<Self>,
18810    ) {
18811        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18812        let ranges = ranges
18813            .into_iter()
18814            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
18815            .collect::<Vec<_>>();
18816        self.fold_creases(ranges, auto_scroll, window, cx);
18817    }
18818
18819    pub fn fold_creases<T: ToOffset + Clone>(
18820        &mut self,
18821        creases: Vec<Crease<T>>,
18822        auto_scroll: bool,
18823        _window: &mut Window,
18824        cx: &mut Context<Self>,
18825    ) {
18826        if creases.is_empty() {
18827            return;
18828        }
18829
18830        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
18831
18832        if auto_scroll {
18833            self.request_autoscroll(Autoscroll::fit(), cx);
18834        }
18835
18836        cx.notify();
18837
18838        self.scrollbar_marker_state.dirty = true;
18839        self.folds_did_change(cx);
18840    }
18841
18842    /// Removes any folds whose ranges intersect any of the given ranges.
18843    pub fn unfold_ranges<T: ToOffset + Clone>(
18844        &mut self,
18845        ranges: &[Range<T>],
18846        inclusive: bool,
18847        auto_scroll: bool,
18848        cx: &mut Context<Self>,
18849    ) {
18850        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
18851            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
18852        });
18853        self.folds_did_change(cx);
18854    }
18855
18856    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18857        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
18858            return;
18859        }
18860        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
18861        self.display_map.update(cx, |display_map, cx| {
18862            display_map.fold_buffers([buffer_id], cx)
18863        });
18864        cx.emit(EditorEvent::BufferFoldToggled {
18865            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
18866            folded: true,
18867        });
18868        cx.notify();
18869    }
18870
18871    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18872        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
18873            return;
18874        }
18875        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
18876        self.display_map.update(cx, |display_map, cx| {
18877            display_map.unfold_buffers([buffer_id], cx);
18878        });
18879        cx.emit(EditorEvent::BufferFoldToggled {
18880            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
18881            folded: false,
18882        });
18883        cx.notify();
18884    }
18885
18886    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
18887        self.display_map.read(cx).is_buffer_folded(buffer)
18888    }
18889
18890    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
18891        self.display_map.read(cx).folded_buffers()
18892    }
18893
18894    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18895        self.display_map.update(cx, |display_map, cx| {
18896            display_map.disable_header_for_buffer(buffer_id, cx);
18897        });
18898        cx.notify();
18899    }
18900
18901    /// Removes any folds with the given ranges.
18902    pub fn remove_folds_with_type<T: ToOffset + Clone>(
18903        &mut self,
18904        ranges: &[Range<T>],
18905        type_id: TypeId,
18906        auto_scroll: bool,
18907        cx: &mut Context<Self>,
18908    ) {
18909        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
18910            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
18911        });
18912        self.folds_did_change(cx);
18913    }
18914
18915    fn remove_folds_with<T: ToOffset + Clone>(
18916        &mut self,
18917        ranges: &[Range<T>],
18918        auto_scroll: bool,
18919        cx: &mut Context<Self>,
18920        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
18921    ) {
18922        if ranges.is_empty() {
18923            return;
18924        }
18925
18926        let mut buffers_affected = HashSet::default();
18927        let multi_buffer = self.buffer().read(cx);
18928        for range in ranges {
18929            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
18930                buffers_affected.insert(buffer.read(cx).remote_id());
18931            };
18932        }
18933
18934        self.display_map.update(cx, update);
18935
18936        if auto_scroll {
18937            self.request_autoscroll(Autoscroll::fit(), cx);
18938        }
18939
18940        cx.notify();
18941        self.scrollbar_marker_state.dirty = true;
18942        self.active_indent_guides_state.dirty = true;
18943    }
18944
18945    pub fn update_renderer_widths(
18946        &mut self,
18947        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
18948        cx: &mut Context<Self>,
18949    ) -> bool {
18950        self.display_map
18951            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
18952    }
18953
18954    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
18955        self.display_map.read(cx).fold_placeholder.clone()
18956    }
18957
18958    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
18959        self.buffer.update(cx, |buffer, cx| {
18960            buffer.set_all_diff_hunks_expanded(cx);
18961        });
18962    }
18963
18964    pub fn expand_all_diff_hunks(
18965        &mut self,
18966        _: &ExpandAllDiffHunks,
18967        _window: &mut Window,
18968        cx: &mut Context<Self>,
18969    ) {
18970        self.buffer.update(cx, |buffer, cx| {
18971            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
18972        });
18973    }
18974
18975    pub fn collapse_all_diff_hunks(
18976        &mut self,
18977        _: &CollapseAllDiffHunks,
18978        _window: &mut Window,
18979        cx: &mut Context<Self>,
18980    ) {
18981        self.buffer.update(cx, |buffer, cx| {
18982            buffer.collapse_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
18983        });
18984    }
18985
18986    pub fn toggle_selected_diff_hunks(
18987        &mut self,
18988        _: &ToggleSelectedDiffHunks,
18989        _window: &mut Window,
18990        cx: &mut Context<Self>,
18991    ) {
18992        let ranges: Vec<_> = self
18993            .selections
18994            .disjoint_anchors()
18995            .iter()
18996            .map(|s| s.range())
18997            .collect();
18998        self.toggle_diff_hunks_in_ranges(ranges, cx);
18999    }
19000
19001    pub fn diff_hunks_in_ranges<'a>(
19002        &'a self,
19003        ranges: &'a [Range<Anchor>],
19004        buffer: &'a MultiBufferSnapshot,
19005    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
19006        ranges.iter().flat_map(move |range| {
19007            let end_excerpt_id = range.end.excerpt_id;
19008            let range = range.to_point(buffer);
19009            let mut peek_end = range.end;
19010            if range.end.row < buffer.max_row().0 {
19011                peek_end = Point::new(range.end.row + 1, 0);
19012            }
19013            buffer
19014                .diff_hunks_in_range(range.start..peek_end)
19015                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
19016        })
19017    }
19018
19019    pub fn has_stageable_diff_hunks_in_ranges(
19020        &self,
19021        ranges: &[Range<Anchor>],
19022        snapshot: &MultiBufferSnapshot,
19023    ) -> bool {
19024        let mut hunks = self.diff_hunks_in_ranges(ranges, snapshot);
19025        hunks.any(|hunk| hunk.status().has_secondary_hunk())
19026    }
19027
19028    pub fn toggle_staged_selected_diff_hunks(
19029        &mut self,
19030        _: &::git::ToggleStaged,
19031        _: &mut Window,
19032        cx: &mut Context<Self>,
19033    ) {
19034        let snapshot = self.buffer.read(cx).snapshot(cx);
19035        let ranges: Vec<_> = self
19036            .selections
19037            .disjoint_anchors()
19038            .iter()
19039            .map(|s| s.range())
19040            .collect();
19041        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
19042        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
19043    }
19044
19045    pub fn set_render_diff_hunk_controls(
19046        &mut self,
19047        render_diff_hunk_controls: RenderDiffHunkControlsFn,
19048        cx: &mut Context<Self>,
19049    ) {
19050        self.render_diff_hunk_controls = render_diff_hunk_controls;
19051        cx.notify();
19052    }
19053
19054    pub fn stage_and_next(
19055        &mut self,
19056        _: &::git::StageAndNext,
19057        window: &mut Window,
19058        cx: &mut Context<Self>,
19059    ) {
19060        self.do_stage_or_unstage_and_next(true, window, cx);
19061    }
19062
19063    pub fn unstage_and_next(
19064        &mut self,
19065        _: &::git::UnstageAndNext,
19066        window: &mut Window,
19067        cx: &mut Context<Self>,
19068    ) {
19069        self.do_stage_or_unstage_and_next(false, window, cx);
19070    }
19071
19072    pub fn stage_or_unstage_diff_hunks(
19073        &mut self,
19074        stage: bool,
19075        ranges: Vec<Range<Anchor>>,
19076        cx: &mut Context<Self>,
19077    ) {
19078        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
19079        cx.spawn(async move |this, cx| {
19080            task.await?;
19081            this.update(cx, |this, cx| {
19082                let snapshot = this.buffer.read(cx).snapshot(cx);
19083                let chunk_by = this
19084                    .diff_hunks_in_ranges(&ranges, &snapshot)
19085                    .chunk_by(|hunk| hunk.buffer_id);
19086                for (buffer_id, hunks) in &chunk_by {
19087                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
19088                }
19089            })
19090        })
19091        .detach_and_log_err(cx);
19092    }
19093
19094    fn save_buffers_for_ranges_if_needed(
19095        &mut self,
19096        ranges: &[Range<Anchor>],
19097        cx: &mut Context<Editor>,
19098    ) -> Task<Result<()>> {
19099        let multibuffer = self.buffer.read(cx);
19100        let snapshot = multibuffer.read(cx);
19101        let buffer_ids: HashSet<_> = ranges
19102            .iter()
19103            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
19104            .collect();
19105        drop(snapshot);
19106
19107        let mut buffers = HashSet::default();
19108        for buffer_id in buffer_ids {
19109            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
19110                let buffer = buffer_entity.read(cx);
19111                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
19112                {
19113                    buffers.insert(buffer_entity);
19114                }
19115            }
19116        }
19117
19118        if let Some(project) = &self.project {
19119            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
19120        } else {
19121            Task::ready(Ok(()))
19122        }
19123    }
19124
19125    fn do_stage_or_unstage_and_next(
19126        &mut self,
19127        stage: bool,
19128        window: &mut Window,
19129        cx: &mut Context<Self>,
19130    ) {
19131        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
19132
19133        if ranges.iter().any(|range| range.start != range.end) {
19134            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
19135            return;
19136        }
19137
19138        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
19139        let snapshot = self.snapshot(window, cx);
19140        let position = self
19141            .selections
19142            .newest::<Point>(&snapshot.display_snapshot)
19143            .head();
19144        let mut row = snapshot
19145            .buffer_snapshot()
19146            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
19147            .find(|hunk| hunk.row_range.start.0 > position.row)
19148            .map(|hunk| hunk.row_range.start);
19149
19150        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
19151        // Outside of the project diff editor, wrap around to the beginning.
19152        if !all_diff_hunks_expanded {
19153            row = row.or_else(|| {
19154                snapshot
19155                    .buffer_snapshot()
19156                    .diff_hunks_in_range(Point::zero()..position)
19157                    .find(|hunk| hunk.row_range.end.0 < position.row)
19158                    .map(|hunk| hunk.row_range.start)
19159            });
19160        }
19161
19162        if let Some(row) = row {
19163            let destination = Point::new(row.0, 0);
19164            let autoscroll = Autoscroll::center();
19165
19166            self.unfold_ranges(&[destination..destination], false, false, cx);
19167            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
19168                s.select_ranges([destination..destination]);
19169            });
19170        }
19171    }
19172
19173    fn do_stage_or_unstage(
19174        &self,
19175        stage: bool,
19176        buffer_id: BufferId,
19177        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
19178        cx: &mut App,
19179    ) -> Option<()> {
19180        let project = self.project()?;
19181        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
19182        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
19183        let buffer_snapshot = buffer.read(cx).snapshot();
19184        let file_exists = buffer_snapshot
19185            .file()
19186            .is_some_and(|file| file.disk_state().exists());
19187        diff.update(cx, |diff, cx| {
19188            diff.stage_or_unstage_hunks(
19189                stage,
19190                &hunks
19191                    .map(|hunk| buffer_diff::DiffHunk {
19192                        buffer_range: hunk.buffer_range,
19193                        diff_base_byte_range: hunk.diff_base_byte_range,
19194                        secondary_status: hunk.secondary_status,
19195                        range: Point::zero()..Point::zero(), // unused
19196                    })
19197                    .collect::<Vec<_>>(),
19198                &buffer_snapshot,
19199                file_exists,
19200                cx,
19201            )
19202        });
19203        None
19204    }
19205
19206    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
19207        let ranges: Vec<_> = self
19208            .selections
19209            .disjoint_anchors()
19210            .iter()
19211            .map(|s| s.range())
19212            .collect();
19213        self.buffer
19214            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
19215    }
19216
19217    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
19218        self.buffer.update(cx, |buffer, cx| {
19219            let ranges = vec![Anchor::min()..Anchor::max()];
19220            if !buffer.all_diff_hunks_expanded()
19221                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
19222            {
19223                buffer.collapse_diff_hunks(ranges, cx);
19224                true
19225            } else {
19226                false
19227            }
19228        })
19229    }
19230
19231    fn toggle_diff_hunks_in_ranges(
19232        &mut self,
19233        ranges: Vec<Range<Anchor>>,
19234        cx: &mut Context<Editor>,
19235    ) {
19236        self.buffer.update(cx, |buffer, cx| {
19237            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
19238            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
19239        })
19240    }
19241
19242    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
19243        self.buffer.update(cx, |buffer, cx| {
19244            let snapshot = buffer.snapshot(cx);
19245            let excerpt_id = range.end.excerpt_id;
19246            let point_range = range.to_point(&snapshot);
19247            let expand = !buffer.single_hunk_is_expanded(range, cx);
19248            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
19249        })
19250    }
19251
19252    pub(crate) fn apply_all_diff_hunks(
19253        &mut self,
19254        _: &ApplyAllDiffHunks,
19255        window: &mut Window,
19256        cx: &mut Context<Self>,
19257    ) {
19258        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19259
19260        let buffers = self.buffer.read(cx).all_buffers();
19261        for branch_buffer in buffers {
19262            branch_buffer.update(cx, |branch_buffer, cx| {
19263                branch_buffer.merge_into_base(Vec::new(), cx);
19264            });
19265        }
19266
19267        if let Some(project) = self.project.clone() {
19268            self.save(
19269                SaveOptions {
19270                    format: true,
19271                    autosave: false,
19272                },
19273                project,
19274                window,
19275                cx,
19276            )
19277            .detach_and_log_err(cx);
19278        }
19279    }
19280
19281    pub(crate) fn apply_selected_diff_hunks(
19282        &mut self,
19283        _: &ApplyDiffHunk,
19284        window: &mut Window,
19285        cx: &mut Context<Self>,
19286    ) {
19287        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19288        let snapshot = self.snapshot(window, cx);
19289        let hunks = snapshot.hunks_for_ranges(
19290            self.selections
19291                .all(&snapshot.display_snapshot)
19292                .into_iter()
19293                .map(|selection| selection.range()),
19294        );
19295        let mut ranges_by_buffer = HashMap::default();
19296        self.transact(window, cx, |editor, _window, cx| {
19297            for hunk in hunks {
19298                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
19299                    ranges_by_buffer
19300                        .entry(buffer.clone())
19301                        .or_insert_with(Vec::new)
19302                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
19303                }
19304            }
19305
19306            for (buffer, ranges) in ranges_by_buffer {
19307                buffer.update(cx, |buffer, cx| {
19308                    buffer.merge_into_base(ranges, cx);
19309                });
19310            }
19311        });
19312
19313        if let Some(project) = self.project.clone() {
19314            self.save(
19315                SaveOptions {
19316                    format: true,
19317                    autosave: false,
19318                },
19319                project,
19320                window,
19321                cx,
19322            )
19323            .detach_and_log_err(cx);
19324        }
19325    }
19326
19327    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
19328        if hovered != self.gutter_hovered {
19329            self.gutter_hovered = hovered;
19330            cx.notify();
19331        }
19332    }
19333
19334    pub fn insert_blocks(
19335        &mut self,
19336        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
19337        autoscroll: Option<Autoscroll>,
19338        cx: &mut Context<Self>,
19339    ) -> Vec<CustomBlockId> {
19340        let blocks = self
19341            .display_map
19342            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
19343        if let Some(autoscroll) = autoscroll {
19344            self.request_autoscroll(autoscroll, cx);
19345        }
19346        cx.notify();
19347        blocks
19348    }
19349
19350    pub fn resize_blocks(
19351        &mut self,
19352        heights: HashMap<CustomBlockId, u32>,
19353        autoscroll: Option<Autoscroll>,
19354        cx: &mut Context<Self>,
19355    ) {
19356        self.display_map
19357            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
19358        if let Some(autoscroll) = autoscroll {
19359            self.request_autoscroll(autoscroll, cx);
19360        }
19361        cx.notify();
19362    }
19363
19364    pub fn replace_blocks(
19365        &mut self,
19366        renderers: HashMap<CustomBlockId, RenderBlock>,
19367        autoscroll: Option<Autoscroll>,
19368        cx: &mut Context<Self>,
19369    ) {
19370        self.display_map
19371            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
19372        if let Some(autoscroll) = autoscroll {
19373            self.request_autoscroll(autoscroll, cx);
19374        }
19375        cx.notify();
19376    }
19377
19378    pub fn remove_blocks(
19379        &mut self,
19380        block_ids: HashSet<CustomBlockId>,
19381        autoscroll: Option<Autoscroll>,
19382        cx: &mut Context<Self>,
19383    ) {
19384        self.display_map.update(cx, |display_map, cx| {
19385            display_map.remove_blocks(block_ids, cx)
19386        });
19387        if let Some(autoscroll) = autoscroll {
19388            self.request_autoscroll(autoscroll, cx);
19389        }
19390        cx.notify();
19391    }
19392
19393    pub fn row_for_block(
19394        &self,
19395        block_id: CustomBlockId,
19396        cx: &mut Context<Self>,
19397    ) -> Option<DisplayRow> {
19398        self.display_map
19399            .update(cx, |map, cx| map.row_for_block(block_id, cx))
19400    }
19401
19402    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
19403        self.focused_block = Some(focused_block);
19404    }
19405
19406    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
19407        self.focused_block.take()
19408    }
19409
19410    pub fn insert_creases(
19411        &mut self,
19412        creases: impl IntoIterator<Item = Crease<Anchor>>,
19413        cx: &mut Context<Self>,
19414    ) -> Vec<CreaseId> {
19415        self.display_map
19416            .update(cx, |map, cx| map.insert_creases(creases, cx))
19417    }
19418
19419    pub fn remove_creases(
19420        &mut self,
19421        ids: impl IntoIterator<Item = CreaseId>,
19422        cx: &mut Context<Self>,
19423    ) -> Vec<(CreaseId, Range<Anchor>)> {
19424        self.display_map
19425            .update(cx, |map, cx| map.remove_creases(ids, cx))
19426    }
19427
19428    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
19429        self.display_map
19430            .update(cx, |map, cx| map.snapshot(cx))
19431            .longest_row()
19432    }
19433
19434    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
19435        self.display_map
19436            .update(cx, |map, cx| map.snapshot(cx))
19437            .max_point()
19438    }
19439
19440    pub fn text(&self, cx: &App) -> String {
19441        self.buffer.read(cx).read(cx).text()
19442    }
19443
19444    pub fn is_empty(&self, cx: &App) -> bool {
19445        self.buffer.read(cx).read(cx).is_empty()
19446    }
19447
19448    pub fn text_option(&self, cx: &App) -> Option<String> {
19449        let text = self.text(cx);
19450        let text = text.trim();
19451
19452        if text.is_empty() {
19453            return None;
19454        }
19455
19456        Some(text.to_string())
19457    }
19458
19459    pub fn set_text(
19460        &mut self,
19461        text: impl Into<Arc<str>>,
19462        window: &mut Window,
19463        cx: &mut Context<Self>,
19464    ) {
19465        self.transact(window, cx, |this, _, cx| {
19466            this.buffer
19467                .read(cx)
19468                .as_singleton()
19469                .expect("you can only call set_text on editors for singleton buffers")
19470                .update(cx, |buffer, cx| buffer.set_text(text, cx));
19471        });
19472    }
19473
19474    pub fn display_text(&self, cx: &mut App) -> String {
19475        self.display_map
19476            .update(cx, |map, cx| map.snapshot(cx))
19477            .text()
19478    }
19479
19480    fn create_minimap(
19481        &self,
19482        minimap_settings: MinimapSettings,
19483        window: &mut Window,
19484        cx: &mut Context<Self>,
19485    ) -> Option<Entity<Self>> {
19486        (minimap_settings.minimap_enabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton)
19487            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
19488    }
19489
19490    fn initialize_new_minimap(
19491        &self,
19492        minimap_settings: MinimapSettings,
19493        window: &mut Window,
19494        cx: &mut Context<Self>,
19495    ) -> Entity<Self> {
19496        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
19497
19498        let mut minimap = Editor::new_internal(
19499            EditorMode::Minimap {
19500                parent: cx.weak_entity(),
19501            },
19502            self.buffer.clone(),
19503            None,
19504            Some(self.display_map.clone()),
19505            window,
19506            cx,
19507        );
19508        minimap.scroll_manager.clone_state(&self.scroll_manager);
19509        minimap.set_text_style_refinement(TextStyleRefinement {
19510            font_size: Some(MINIMAP_FONT_SIZE),
19511            font_weight: Some(MINIMAP_FONT_WEIGHT),
19512            ..Default::default()
19513        });
19514        minimap.update_minimap_configuration(minimap_settings, cx);
19515        cx.new(|_| minimap)
19516    }
19517
19518    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
19519        let current_line_highlight = minimap_settings
19520            .current_line_highlight
19521            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
19522        self.set_current_line_highlight(Some(current_line_highlight));
19523    }
19524
19525    pub fn minimap(&self) -> Option<&Entity<Self>> {
19526        self.minimap
19527            .as_ref()
19528            .filter(|_| self.minimap_visibility.visible())
19529    }
19530
19531    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
19532        let mut wrap_guides = smallvec![];
19533
19534        if self.show_wrap_guides == Some(false) {
19535            return wrap_guides;
19536        }
19537
19538        let settings = self.buffer.read(cx).language_settings(cx);
19539        if settings.show_wrap_guides {
19540            match self.soft_wrap_mode(cx) {
19541                SoftWrap::Column(soft_wrap) => {
19542                    wrap_guides.push((soft_wrap as usize, true));
19543                }
19544                SoftWrap::Bounded(soft_wrap) => {
19545                    wrap_guides.push((soft_wrap as usize, true));
19546                }
19547                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
19548            }
19549            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
19550        }
19551
19552        wrap_guides
19553    }
19554
19555    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
19556        let settings = self.buffer.read(cx).language_settings(cx);
19557        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
19558        match mode {
19559            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
19560                SoftWrap::None
19561            }
19562            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
19563            language_settings::SoftWrap::PreferredLineLength => {
19564                SoftWrap::Column(settings.preferred_line_length)
19565            }
19566            language_settings::SoftWrap::Bounded => {
19567                SoftWrap::Bounded(settings.preferred_line_length)
19568            }
19569        }
19570    }
19571
19572    pub fn set_soft_wrap_mode(
19573        &mut self,
19574        mode: language_settings::SoftWrap,
19575
19576        cx: &mut Context<Self>,
19577    ) {
19578        self.soft_wrap_mode_override = Some(mode);
19579        cx.notify();
19580    }
19581
19582    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
19583        self.hard_wrap = hard_wrap;
19584        cx.notify();
19585    }
19586
19587    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
19588        self.text_style_refinement = Some(style);
19589    }
19590
19591    /// called by the Element so we know what style we were most recently rendered with.
19592    pub fn set_style(&mut self, style: EditorStyle, window: &mut Window, cx: &mut Context<Self>) {
19593        // We intentionally do not inform the display map about the minimap style
19594        // so that wrapping is not recalculated and stays consistent for the editor
19595        // and its linked minimap.
19596        if !self.mode.is_minimap() {
19597            let font = style.text.font();
19598            let font_size = style.text.font_size.to_pixels(window.rem_size());
19599            let display_map = self
19600                .placeholder_display_map
19601                .as_ref()
19602                .filter(|_| self.is_empty(cx))
19603                .unwrap_or(&self.display_map);
19604
19605            display_map.update(cx, |map, cx| map.set_font(font, font_size, cx));
19606        }
19607        self.style = Some(style);
19608    }
19609
19610    pub fn style(&self) -> Option<&EditorStyle> {
19611        self.style.as_ref()
19612    }
19613
19614    // Called by the element. This method is not designed to be called outside of the editor
19615    // element's layout code because it does not notify when rewrapping is computed synchronously.
19616    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
19617        if self.is_empty(cx) {
19618            self.placeholder_display_map
19619                .as_ref()
19620                .map_or(false, |display_map| {
19621                    display_map.update(cx, |map, cx| map.set_wrap_width(width, cx))
19622                })
19623        } else {
19624            self.display_map
19625                .update(cx, |map, cx| map.set_wrap_width(width, cx))
19626        }
19627    }
19628
19629    pub fn set_soft_wrap(&mut self) {
19630        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
19631    }
19632
19633    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
19634        if self.soft_wrap_mode_override.is_some() {
19635            self.soft_wrap_mode_override.take();
19636        } else {
19637            let soft_wrap = match self.soft_wrap_mode(cx) {
19638                SoftWrap::GitDiff => return,
19639                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
19640                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
19641                    language_settings::SoftWrap::None
19642                }
19643            };
19644            self.soft_wrap_mode_override = Some(soft_wrap);
19645        }
19646        cx.notify();
19647    }
19648
19649    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
19650        let Some(workspace) = self.workspace() else {
19651            return;
19652        };
19653        let fs = workspace.read(cx).app_state().fs.clone();
19654        let current_show = TabBarSettings::get_global(cx).show;
19655        update_settings_file(fs, cx, move |setting, _| {
19656            setting.tab_bar.get_or_insert_default().show = Some(!current_show);
19657        });
19658    }
19659
19660    pub fn toggle_indent_guides(
19661        &mut self,
19662        _: &ToggleIndentGuides,
19663        _: &mut Window,
19664        cx: &mut Context<Self>,
19665    ) {
19666        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
19667            self.buffer
19668                .read(cx)
19669                .language_settings(cx)
19670                .indent_guides
19671                .enabled
19672        });
19673        self.show_indent_guides = Some(!currently_enabled);
19674        cx.notify();
19675    }
19676
19677    fn should_show_indent_guides(&self) -> Option<bool> {
19678        self.show_indent_guides
19679    }
19680
19681    pub fn toggle_line_numbers(
19682        &mut self,
19683        _: &ToggleLineNumbers,
19684        _: &mut Window,
19685        cx: &mut Context<Self>,
19686    ) {
19687        let mut editor_settings = EditorSettings::get_global(cx).clone();
19688        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
19689        EditorSettings::override_global(editor_settings, cx);
19690    }
19691
19692    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
19693        if let Some(show_line_numbers) = self.show_line_numbers {
19694            return show_line_numbers;
19695        }
19696        EditorSettings::get_global(cx).gutter.line_numbers
19697    }
19698
19699    pub fn relative_line_numbers(&self, cx: &mut App) -> RelativeLineNumbers {
19700        match (
19701            self.use_relative_line_numbers,
19702            EditorSettings::get_global(cx).relative_line_numbers,
19703        ) {
19704            (None, setting) => setting,
19705            (Some(false), _) => RelativeLineNumbers::Disabled,
19706            (Some(true), RelativeLineNumbers::Wrapped) => RelativeLineNumbers::Wrapped,
19707            (Some(true), _) => RelativeLineNumbers::Enabled,
19708        }
19709    }
19710
19711    pub fn toggle_relative_line_numbers(
19712        &mut self,
19713        _: &ToggleRelativeLineNumbers,
19714        _: &mut Window,
19715        cx: &mut Context<Self>,
19716    ) {
19717        let is_relative = self.relative_line_numbers(cx);
19718        self.set_relative_line_number(Some(!is_relative.enabled()), cx)
19719    }
19720
19721    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
19722        self.use_relative_line_numbers = is_relative;
19723        cx.notify();
19724    }
19725
19726    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
19727        self.show_gutter = show_gutter;
19728        cx.notify();
19729    }
19730
19731    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
19732        self.show_scrollbars = ScrollbarAxes {
19733            horizontal: show,
19734            vertical: show,
19735        };
19736        cx.notify();
19737    }
19738
19739    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
19740        self.show_scrollbars.vertical = show;
19741        cx.notify();
19742    }
19743
19744    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
19745        self.show_scrollbars.horizontal = show;
19746        cx.notify();
19747    }
19748
19749    pub fn set_minimap_visibility(
19750        &mut self,
19751        minimap_visibility: MinimapVisibility,
19752        window: &mut Window,
19753        cx: &mut Context<Self>,
19754    ) {
19755        if self.minimap_visibility != minimap_visibility {
19756            if minimap_visibility.visible() && self.minimap.is_none() {
19757                let minimap_settings = EditorSettings::get_global(cx).minimap;
19758                self.minimap =
19759                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
19760            }
19761            self.minimap_visibility = minimap_visibility;
19762            cx.notify();
19763        }
19764    }
19765
19766    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19767        self.set_show_scrollbars(false, cx);
19768        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
19769    }
19770
19771    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19772        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
19773    }
19774
19775    /// Normally the text in full mode and auto height editors is padded on the
19776    /// left side by roughly half a character width for improved hit testing.
19777    ///
19778    /// Use this method to disable this for cases where this is not wanted (e.g.
19779    /// if you want to align the editor text with some other text above or below)
19780    /// or if you want to add this padding to single-line editors.
19781    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
19782        self.offset_content = offset_content;
19783        cx.notify();
19784    }
19785
19786    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
19787        self.show_line_numbers = Some(show_line_numbers);
19788        cx.notify();
19789    }
19790
19791    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
19792        self.disable_expand_excerpt_buttons = true;
19793        cx.notify();
19794    }
19795
19796    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
19797        self.show_git_diff_gutter = Some(show_git_diff_gutter);
19798        cx.notify();
19799    }
19800
19801    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
19802        self.show_code_actions = Some(show_code_actions);
19803        cx.notify();
19804    }
19805
19806    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
19807        self.show_runnables = Some(show_runnables);
19808        cx.notify();
19809    }
19810
19811    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
19812        self.show_breakpoints = Some(show_breakpoints);
19813        cx.notify();
19814    }
19815
19816    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
19817        if self.display_map.read(cx).masked != masked {
19818            self.display_map.update(cx, |map, _| map.masked = masked);
19819        }
19820        cx.notify()
19821    }
19822
19823    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
19824        self.show_wrap_guides = Some(show_wrap_guides);
19825        cx.notify();
19826    }
19827
19828    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
19829        self.show_indent_guides = Some(show_indent_guides);
19830        cx.notify();
19831    }
19832
19833    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
19834        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
19835            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local())
19836                && let Some(dir) = file.abs_path(cx).parent()
19837            {
19838                return Some(dir.to_owned());
19839            }
19840        }
19841
19842        None
19843    }
19844
19845    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
19846        self.active_excerpt(cx)?
19847            .1
19848            .read(cx)
19849            .file()
19850            .and_then(|f| f.as_local())
19851    }
19852
19853    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
19854        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
19855            let buffer = buffer.read(cx);
19856            if let Some(project_path) = buffer.project_path(cx) {
19857                let project = self.project()?.read(cx);
19858                project.absolute_path(&project_path, cx)
19859            } else {
19860                buffer
19861                    .file()
19862                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
19863            }
19864        })
19865    }
19866
19867    pub fn reveal_in_finder(
19868        &mut self,
19869        _: &RevealInFileManager,
19870        _window: &mut Window,
19871        cx: &mut Context<Self>,
19872    ) {
19873        if let Some(target) = self.target_file(cx) {
19874            cx.reveal_path(&target.abs_path(cx));
19875        }
19876    }
19877
19878    pub fn copy_path(
19879        &mut self,
19880        _: &zed_actions::workspace::CopyPath,
19881        _window: &mut Window,
19882        cx: &mut Context<Self>,
19883    ) {
19884        if let Some(path) = self.target_file_abs_path(cx)
19885            && let Some(path) = path.to_str()
19886        {
19887            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
19888        } else {
19889            cx.propagate();
19890        }
19891    }
19892
19893    pub fn copy_relative_path(
19894        &mut self,
19895        _: &zed_actions::workspace::CopyRelativePath,
19896        _window: &mut Window,
19897        cx: &mut Context<Self>,
19898    ) {
19899        if let Some(path) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
19900            let project = self.project()?.read(cx);
19901            let path = buffer.read(cx).file()?.path();
19902            let path = path.display(project.path_style(cx));
19903            Some(path)
19904        }) {
19905            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
19906        } else {
19907            cx.propagate();
19908        }
19909    }
19910
19911    /// Returns the project path for the editor's buffer, if any buffer is
19912    /// opened in the editor.
19913    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
19914        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
19915            buffer.read(cx).project_path(cx)
19916        } else {
19917            None
19918        }
19919    }
19920
19921    // Returns true if the editor handled a go-to-line request
19922    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
19923        maybe!({
19924            let breakpoint_store = self.breakpoint_store.as_ref()?;
19925
19926            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
19927            else {
19928                self.clear_row_highlights::<ActiveDebugLine>();
19929                return None;
19930            };
19931
19932            let position = active_stack_frame.position;
19933            let buffer_id = position.buffer_id?;
19934            let snapshot = self
19935                .project
19936                .as_ref()?
19937                .read(cx)
19938                .buffer_for_id(buffer_id, cx)?
19939                .read(cx)
19940                .snapshot();
19941
19942            let mut handled = false;
19943            for (id, ExcerptRange { context, .. }) in
19944                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
19945            {
19946                if context.start.cmp(&position, &snapshot).is_ge()
19947                    || context.end.cmp(&position, &snapshot).is_lt()
19948                {
19949                    continue;
19950                }
19951                let snapshot = self.buffer.read(cx).snapshot(cx);
19952                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
19953
19954                handled = true;
19955                self.clear_row_highlights::<ActiveDebugLine>();
19956
19957                self.go_to_line::<ActiveDebugLine>(
19958                    multibuffer_anchor,
19959                    Some(cx.theme().colors().editor_debugger_active_line_background),
19960                    window,
19961                    cx,
19962                );
19963
19964                cx.notify();
19965            }
19966
19967            handled.then_some(())
19968        })
19969        .is_some()
19970    }
19971
19972    pub fn copy_file_name_without_extension(
19973        &mut self,
19974        _: &CopyFileNameWithoutExtension,
19975        _: &mut Window,
19976        cx: &mut Context<Self>,
19977    ) {
19978        if let Some(file) = self.target_file(cx)
19979            && let Some(file_stem) = file.path().file_stem()
19980        {
19981            cx.write_to_clipboard(ClipboardItem::new_string(file_stem.to_string()));
19982        }
19983    }
19984
19985    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
19986        if let Some(file) = self.target_file(cx)
19987            && let Some(name) = file.path().file_name()
19988        {
19989            cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
19990        }
19991    }
19992
19993    pub fn toggle_git_blame(
19994        &mut self,
19995        _: &::git::Blame,
19996        window: &mut Window,
19997        cx: &mut Context<Self>,
19998    ) {
19999        self.show_git_blame_gutter = !self.show_git_blame_gutter;
20000
20001        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
20002            self.start_git_blame(true, window, cx);
20003        }
20004
20005        cx.notify();
20006    }
20007
20008    pub fn toggle_git_blame_inline(
20009        &mut self,
20010        _: &ToggleGitBlameInline,
20011        window: &mut Window,
20012        cx: &mut Context<Self>,
20013    ) {
20014        self.toggle_git_blame_inline_internal(true, window, cx);
20015        cx.notify();
20016    }
20017
20018    pub fn open_git_blame_commit(
20019        &mut self,
20020        _: &OpenGitBlameCommit,
20021        window: &mut Window,
20022        cx: &mut Context<Self>,
20023    ) {
20024        self.open_git_blame_commit_internal(window, cx);
20025    }
20026
20027    fn open_git_blame_commit_internal(
20028        &mut self,
20029        window: &mut Window,
20030        cx: &mut Context<Self>,
20031    ) -> Option<()> {
20032        let blame = self.blame.as_ref()?;
20033        let snapshot = self.snapshot(window, cx);
20034        let cursor = self
20035            .selections
20036            .newest::<Point>(&snapshot.display_snapshot)
20037            .head();
20038        let (buffer, point, _) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)?;
20039        let (_, blame_entry) = blame
20040            .update(cx, |blame, cx| {
20041                blame
20042                    .blame_for_rows(
20043                        &[RowInfo {
20044                            buffer_id: Some(buffer.remote_id()),
20045                            buffer_row: Some(point.row),
20046                            ..Default::default()
20047                        }],
20048                        cx,
20049                    )
20050                    .next()
20051            })
20052            .flatten()?;
20053        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
20054        let repo = blame.read(cx).repository(cx, buffer.remote_id())?;
20055        let workspace = self.workspace()?.downgrade();
20056        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
20057        None
20058    }
20059
20060    pub fn git_blame_inline_enabled(&self) -> bool {
20061        self.git_blame_inline_enabled
20062    }
20063
20064    pub fn toggle_selection_menu(
20065        &mut self,
20066        _: &ToggleSelectionMenu,
20067        _: &mut Window,
20068        cx: &mut Context<Self>,
20069    ) {
20070        self.show_selection_menu = self
20071            .show_selection_menu
20072            .map(|show_selections_menu| !show_selections_menu)
20073            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
20074
20075        cx.notify();
20076    }
20077
20078    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
20079        self.show_selection_menu
20080            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
20081    }
20082
20083    fn start_git_blame(
20084        &mut self,
20085        user_triggered: bool,
20086        window: &mut Window,
20087        cx: &mut Context<Self>,
20088    ) {
20089        if let Some(project) = self.project() {
20090            if let Some(buffer) = self.buffer().read(cx).as_singleton()
20091                && buffer.read(cx).file().is_none()
20092            {
20093                return;
20094            }
20095
20096            let focused = self.focus_handle(cx).contains_focused(window, cx);
20097
20098            let project = project.clone();
20099            let blame = cx
20100                .new(|cx| GitBlame::new(self.buffer.clone(), project, user_triggered, focused, cx));
20101            self.blame_subscription =
20102                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
20103            self.blame = Some(blame);
20104        }
20105    }
20106
20107    fn toggle_git_blame_inline_internal(
20108        &mut self,
20109        user_triggered: bool,
20110        window: &mut Window,
20111        cx: &mut Context<Self>,
20112    ) {
20113        if self.git_blame_inline_enabled {
20114            self.git_blame_inline_enabled = false;
20115            self.show_git_blame_inline = false;
20116            self.show_git_blame_inline_delay_task.take();
20117        } else {
20118            self.git_blame_inline_enabled = true;
20119            self.start_git_blame_inline(user_triggered, window, cx);
20120        }
20121
20122        cx.notify();
20123    }
20124
20125    fn start_git_blame_inline(
20126        &mut self,
20127        user_triggered: bool,
20128        window: &mut Window,
20129        cx: &mut Context<Self>,
20130    ) {
20131        self.start_git_blame(user_triggered, window, cx);
20132
20133        if ProjectSettings::get_global(cx)
20134            .git
20135            .inline_blame_delay()
20136            .is_some()
20137        {
20138            self.start_inline_blame_timer(window, cx);
20139        } else {
20140            self.show_git_blame_inline = true
20141        }
20142    }
20143
20144    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
20145        self.blame.as_ref()
20146    }
20147
20148    pub fn show_git_blame_gutter(&self) -> bool {
20149        self.show_git_blame_gutter
20150    }
20151
20152    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
20153        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
20154    }
20155
20156    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
20157        self.show_git_blame_inline
20158            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
20159            && !self.newest_selection_head_on_empty_line(cx)
20160            && self.has_blame_entries(cx)
20161    }
20162
20163    fn has_blame_entries(&self, cx: &App) -> bool {
20164        self.blame()
20165            .is_some_and(|blame| blame.read(cx).has_generated_entries())
20166    }
20167
20168    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
20169        let cursor_anchor = self.selections.newest_anchor().head();
20170
20171        let snapshot = self.buffer.read(cx).snapshot(cx);
20172        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
20173
20174        snapshot.line_len(buffer_row) == 0
20175    }
20176
20177    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
20178        let buffer_and_selection = maybe!({
20179            let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
20180            let selection_range = selection.range();
20181
20182            let multi_buffer = self.buffer().read(cx);
20183            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
20184            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
20185
20186            let (buffer, range, _) = if selection.reversed {
20187                buffer_ranges.first()
20188            } else {
20189                buffer_ranges.last()
20190            }?;
20191
20192            let selection = text::ToPoint::to_point(&range.start, buffer).row
20193                ..text::ToPoint::to_point(&range.end, buffer).row;
20194            Some((multi_buffer.buffer(buffer.remote_id()).unwrap(), selection))
20195        });
20196
20197        let Some((buffer, selection)) = buffer_and_selection else {
20198            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
20199        };
20200
20201        let Some(project) = self.project() else {
20202            return Task::ready(Err(anyhow!("editor does not have project")));
20203        };
20204
20205        project.update(cx, |project, cx| {
20206            project.get_permalink_to_line(&buffer, selection, cx)
20207        })
20208    }
20209
20210    pub fn copy_permalink_to_line(
20211        &mut self,
20212        _: &CopyPermalinkToLine,
20213        window: &mut Window,
20214        cx: &mut Context<Self>,
20215    ) {
20216        let permalink_task = self.get_permalink_to_line(cx);
20217        let workspace = self.workspace();
20218
20219        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
20220            Ok(permalink) => {
20221                cx.update(|_, cx| {
20222                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
20223                })
20224                .ok();
20225            }
20226            Err(err) => {
20227                let message = format!("Failed to copy permalink: {err}");
20228
20229                anyhow::Result::<()>::Err(err).log_err();
20230
20231                if let Some(workspace) = workspace {
20232                    workspace
20233                        .update_in(cx, |workspace, _, cx| {
20234                            struct CopyPermalinkToLine;
20235
20236                            workspace.show_toast(
20237                                Toast::new(
20238                                    NotificationId::unique::<CopyPermalinkToLine>(),
20239                                    message,
20240                                ),
20241                                cx,
20242                            )
20243                        })
20244                        .ok();
20245                }
20246            }
20247        })
20248        .detach();
20249    }
20250
20251    pub fn copy_file_location(
20252        &mut self,
20253        _: &CopyFileLocation,
20254        _: &mut Window,
20255        cx: &mut Context<Self>,
20256    ) {
20257        let selection = self
20258            .selections
20259            .newest::<Point>(&self.display_snapshot(cx))
20260            .start
20261            .row
20262            + 1;
20263        if let Some(file) = self.target_file(cx) {
20264            let path = file.path().display(file.path_style(cx));
20265            cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
20266        }
20267    }
20268
20269    pub fn open_permalink_to_line(
20270        &mut self,
20271        _: &OpenPermalinkToLine,
20272        window: &mut Window,
20273        cx: &mut Context<Self>,
20274    ) {
20275        let permalink_task = self.get_permalink_to_line(cx);
20276        let workspace = self.workspace();
20277
20278        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
20279            Ok(permalink) => {
20280                cx.update(|_, cx| {
20281                    cx.open_url(permalink.as_ref());
20282                })
20283                .ok();
20284            }
20285            Err(err) => {
20286                let message = format!("Failed to open permalink: {err}");
20287
20288                anyhow::Result::<()>::Err(err).log_err();
20289
20290                if let Some(workspace) = workspace {
20291                    workspace
20292                        .update(cx, |workspace, cx| {
20293                            struct OpenPermalinkToLine;
20294
20295                            workspace.show_toast(
20296                                Toast::new(
20297                                    NotificationId::unique::<OpenPermalinkToLine>(),
20298                                    message,
20299                                ),
20300                                cx,
20301                            )
20302                        })
20303                        .ok();
20304                }
20305            }
20306        })
20307        .detach();
20308    }
20309
20310    pub fn insert_uuid_v4(
20311        &mut self,
20312        _: &InsertUuidV4,
20313        window: &mut Window,
20314        cx: &mut Context<Self>,
20315    ) {
20316        self.insert_uuid(UuidVersion::V4, window, cx);
20317    }
20318
20319    pub fn insert_uuid_v7(
20320        &mut self,
20321        _: &InsertUuidV7,
20322        window: &mut Window,
20323        cx: &mut Context<Self>,
20324    ) {
20325        self.insert_uuid(UuidVersion::V7, window, cx);
20326    }
20327
20328    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
20329        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
20330        self.transact(window, cx, |this, window, cx| {
20331            let edits = this
20332                .selections
20333                .all::<Point>(&this.display_snapshot(cx))
20334                .into_iter()
20335                .map(|selection| {
20336                    let uuid = match version {
20337                        UuidVersion::V4 => uuid::Uuid::new_v4(),
20338                        UuidVersion::V7 => uuid::Uuid::now_v7(),
20339                    };
20340
20341                    (selection.range(), uuid.to_string())
20342                });
20343            this.edit(edits, cx);
20344            this.refresh_edit_prediction(true, false, window, cx);
20345        });
20346    }
20347
20348    pub fn open_selections_in_multibuffer(
20349        &mut self,
20350        _: &OpenSelectionsInMultibuffer,
20351        window: &mut Window,
20352        cx: &mut Context<Self>,
20353    ) {
20354        let multibuffer = self.buffer.read(cx);
20355
20356        let Some(buffer) = multibuffer.as_singleton() else {
20357            return;
20358        };
20359
20360        let Some(workspace) = self.workspace() else {
20361            return;
20362        };
20363
20364        let title = multibuffer.title(cx).to_string();
20365
20366        let locations = self
20367            .selections
20368            .all_anchors(&self.display_snapshot(cx))
20369            .iter()
20370            .map(|selection| {
20371                (
20372                    buffer.clone(),
20373                    (selection.start.text_anchor..selection.end.text_anchor)
20374                        .to_point(buffer.read(cx)),
20375                )
20376            })
20377            .into_group_map();
20378
20379        cx.spawn_in(window, async move |_, cx| {
20380            workspace.update_in(cx, |workspace, window, cx| {
20381                Self::open_locations_in_multibuffer(
20382                    workspace,
20383                    locations,
20384                    format!("Selections for '{title}'"),
20385                    false,
20386                    MultibufferSelectionMode::All,
20387                    window,
20388                    cx,
20389                );
20390            })
20391        })
20392        .detach();
20393    }
20394
20395    /// Adds a row highlight for the given range. If a row has multiple highlights, the
20396    /// last highlight added will be used.
20397    ///
20398    /// If the range ends at the beginning of a line, then that line will not be highlighted.
20399    pub fn highlight_rows<T: 'static>(
20400        &mut self,
20401        range: Range<Anchor>,
20402        color: Hsla,
20403        options: RowHighlightOptions,
20404        cx: &mut Context<Self>,
20405    ) {
20406        let snapshot = self.buffer().read(cx).snapshot(cx);
20407        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
20408        let ix = row_highlights.binary_search_by(|highlight| {
20409            Ordering::Equal
20410                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
20411                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
20412        });
20413
20414        if let Err(mut ix) = ix {
20415            let index = post_inc(&mut self.highlight_order);
20416
20417            // If this range intersects with the preceding highlight, then merge it with
20418            // the preceding highlight. Otherwise insert a new highlight.
20419            let mut merged = false;
20420            if ix > 0 {
20421                let prev_highlight = &mut row_highlights[ix - 1];
20422                if prev_highlight
20423                    .range
20424                    .end
20425                    .cmp(&range.start, &snapshot)
20426                    .is_ge()
20427                {
20428                    ix -= 1;
20429                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
20430                        prev_highlight.range.end = range.end;
20431                    }
20432                    merged = true;
20433                    prev_highlight.index = index;
20434                    prev_highlight.color = color;
20435                    prev_highlight.options = options;
20436                }
20437            }
20438
20439            if !merged {
20440                row_highlights.insert(
20441                    ix,
20442                    RowHighlight {
20443                        range,
20444                        index,
20445                        color,
20446                        options,
20447                        type_id: TypeId::of::<T>(),
20448                    },
20449                );
20450            }
20451
20452            // If any of the following highlights intersect with this one, merge them.
20453            while let Some(next_highlight) = row_highlights.get(ix + 1) {
20454                let highlight = &row_highlights[ix];
20455                if next_highlight
20456                    .range
20457                    .start
20458                    .cmp(&highlight.range.end, &snapshot)
20459                    .is_le()
20460                {
20461                    if next_highlight
20462                        .range
20463                        .end
20464                        .cmp(&highlight.range.end, &snapshot)
20465                        .is_gt()
20466                    {
20467                        row_highlights[ix].range.end = next_highlight.range.end;
20468                    }
20469                    row_highlights.remove(ix + 1);
20470                } else {
20471                    break;
20472                }
20473            }
20474        }
20475    }
20476
20477    /// Remove any highlighted row ranges of the given type that intersect the
20478    /// given ranges.
20479    pub fn remove_highlighted_rows<T: 'static>(
20480        &mut self,
20481        ranges_to_remove: Vec<Range<Anchor>>,
20482        cx: &mut Context<Self>,
20483    ) {
20484        let snapshot = self.buffer().read(cx).snapshot(cx);
20485        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
20486        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
20487        row_highlights.retain(|highlight| {
20488            while let Some(range_to_remove) = ranges_to_remove.peek() {
20489                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
20490                    Ordering::Less | Ordering::Equal => {
20491                        ranges_to_remove.next();
20492                    }
20493                    Ordering::Greater => {
20494                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
20495                            Ordering::Less | Ordering::Equal => {
20496                                return false;
20497                            }
20498                            Ordering::Greater => break,
20499                        }
20500                    }
20501                }
20502            }
20503
20504            true
20505        })
20506    }
20507
20508    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
20509    pub fn clear_row_highlights<T: 'static>(&mut self) {
20510        self.highlighted_rows.remove(&TypeId::of::<T>());
20511    }
20512
20513    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
20514    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
20515        self.highlighted_rows
20516            .get(&TypeId::of::<T>())
20517            .map_or(&[] as &[_], |vec| vec.as_slice())
20518            .iter()
20519            .map(|highlight| (highlight.range.clone(), highlight.color))
20520    }
20521
20522    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
20523    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
20524    /// Allows to ignore certain kinds of highlights.
20525    pub fn highlighted_display_rows(
20526        &self,
20527        window: &mut Window,
20528        cx: &mut App,
20529    ) -> BTreeMap<DisplayRow, LineHighlight> {
20530        let snapshot = self.snapshot(window, cx);
20531        let mut used_highlight_orders = HashMap::default();
20532        self.highlighted_rows
20533            .iter()
20534            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
20535            .fold(
20536                BTreeMap::<DisplayRow, LineHighlight>::new(),
20537                |mut unique_rows, highlight| {
20538                    let start = highlight.range.start.to_display_point(&snapshot);
20539                    let end = highlight.range.end.to_display_point(&snapshot);
20540                    let start_row = start.row().0;
20541                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
20542                        && end.column() == 0
20543                    {
20544                        end.row().0.saturating_sub(1)
20545                    } else {
20546                        end.row().0
20547                    };
20548                    for row in start_row..=end_row {
20549                        let used_index =
20550                            used_highlight_orders.entry(row).or_insert(highlight.index);
20551                        if highlight.index >= *used_index {
20552                            *used_index = highlight.index;
20553                            unique_rows.insert(
20554                                DisplayRow(row),
20555                                LineHighlight {
20556                                    include_gutter: highlight.options.include_gutter,
20557                                    border: None,
20558                                    background: highlight.color.into(),
20559                                    type_id: Some(highlight.type_id),
20560                                },
20561                            );
20562                        }
20563                    }
20564                    unique_rows
20565                },
20566            )
20567    }
20568
20569    pub fn highlighted_display_row_for_autoscroll(
20570        &self,
20571        snapshot: &DisplaySnapshot,
20572    ) -> Option<DisplayRow> {
20573        self.highlighted_rows
20574            .values()
20575            .flat_map(|highlighted_rows| highlighted_rows.iter())
20576            .filter_map(|highlight| {
20577                if highlight.options.autoscroll {
20578                    Some(highlight.range.start.to_display_point(snapshot).row())
20579                } else {
20580                    None
20581                }
20582            })
20583            .min()
20584    }
20585
20586    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
20587        self.highlight_background::<SearchWithinRange>(
20588            ranges,
20589            |colors| colors.colors().editor_document_highlight_read_background,
20590            cx,
20591        )
20592    }
20593
20594    pub fn set_breadcrumb_header(&mut self, new_header: String) {
20595        self.breadcrumb_header = Some(new_header);
20596    }
20597
20598    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
20599        self.clear_background_highlights::<SearchWithinRange>(cx);
20600    }
20601
20602    pub fn highlight_background<T: 'static>(
20603        &mut self,
20604        ranges: &[Range<Anchor>],
20605        color_fetcher: fn(&Theme) -> Hsla,
20606        cx: &mut Context<Self>,
20607    ) {
20608        self.background_highlights.insert(
20609            HighlightKey::Type(TypeId::of::<T>()),
20610            (color_fetcher, Arc::from(ranges)),
20611        );
20612        self.scrollbar_marker_state.dirty = true;
20613        cx.notify();
20614    }
20615
20616    pub fn highlight_background_key<T: 'static>(
20617        &mut self,
20618        key: usize,
20619        ranges: &[Range<Anchor>],
20620        color_fetcher: fn(&Theme) -> Hsla,
20621        cx: &mut Context<Self>,
20622    ) {
20623        self.background_highlights.insert(
20624            HighlightKey::TypePlus(TypeId::of::<T>(), key),
20625            (color_fetcher, Arc::from(ranges)),
20626        );
20627        self.scrollbar_marker_state.dirty = true;
20628        cx.notify();
20629    }
20630
20631    pub fn clear_background_highlights<T: 'static>(
20632        &mut self,
20633        cx: &mut Context<Self>,
20634    ) -> Option<BackgroundHighlight> {
20635        let text_highlights = self
20636            .background_highlights
20637            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
20638        if !text_highlights.1.is_empty() {
20639            self.scrollbar_marker_state.dirty = true;
20640            cx.notify();
20641        }
20642        Some(text_highlights)
20643    }
20644
20645    pub fn highlight_gutter<T: 'static>(
20646        &mut self,
20647        ranges: impl Into<Vec<Range<Anchor>>>,
20648        color_fetcher: fn(&App) -> Hsla,
20649        cx: &mut Context<Self>,
20650    ) {
20651        self.gutter_highlights
20652            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
20653        cx.notify();
20654    }
20655
20656    pub fn clear_gutter_highlights<T: 'static>(
20657        &mut self,
20658        cx: &mut Context<Self>,
20659    ) -> Option<GutterHighlight> {
20660        cx.notify();
20661        self.gutter_highlights.remove(&TypeId::of::<T>())
20662    }
20663
20664    pub fn insert_gutter_highlight<T: 'static>(
20665        &mut self,
20666        range: Range<Anchor>,
20667        color_fetcher: fn(&App) -> Hsla,
20668        cx: &mut Context<Self>,
20669    ) {
20670        let snapshot = self.buffer().read(cx).snapshot(cx);
20671        let mut highlights = self
20672            .gutter_highlights
20673            .remove(&TypeId::of::<T>())
20674            .map(|(_, highlights)| highlights)
20675            .unwrap_or_default();
20676        let ix = highlights.binary_search_by(|highlight| {
20677            Ordering::Equal
20678                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
20679                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
20680        });
20681        if let Err(ix) = ix {
20682            highlights.insert(ix, range);
20683        }
20684        self.gutter_highlights
20685            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
20686    }
20687
20688    pub fn remove_gutter_highlights<T: 'static>(
20689        &mut self,
20690        ranges_to_remove: Vec<Range<Anchor>>,
20691        cx: &mut Context<Self>,
20692    ) {
20693        let snapshot = self.buffer().read(cx).snapshot(cx);
20694        let Some((color_fetcher, mut gutter_highlights)) =
20695            self.gutter_highlights.remove(&TypeId::of::<T>())
20696        else {
20697            return;
20698        };
20699        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
20700        gutter_highlights.retain(|highlight| {
20701            while let Some(range_to_remove) = ranges_to_remove.peek() {
20702                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
20703                    Ordering::Less | Ordering::Equal => {
20704                        ranges_to_remove.next();
20705                    }
20706                    Ordering::Greater => {
20707                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
20708                            Ordering::Less | Ordering::Equal => {
20709                                return false;
20710                            }
20711                            Ordering::Greater => break,
20712                        }
20713                    }
20714                }
20715            }
20716
20717            true
20718        });
20719        self.gutter_highlights
20720            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
20721    }
20722
20723    #[cfg(feature = "test-support")]
20724    pub fn all_text_highlights(
20725        &self,
20726        window: &mut Window,
20727        cx: &mut Context<Self>,
20728    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
20729        let snapshot = self.snapshot(window, cx);
20730        self.display_map.update(cx, |display_map, _| {
20731            display_map
20732                .all_text_highlights()
20733                .map(|highlight| {
20734                    let (style, ranges) = highlight.as_ref();
20735                    (
20736                        *style,
20737                        ranges
20738                            .iter()
20739                            .map(|range| range.clone().to_display_points(&snapshot))
20740                            .collect(),
20741                    )
20742                })
20743                .collect()
20744        })
20745    }
20746
20747    #[cfg(feature = "test-support")]
20748    pub fn all_text_background_highlights(
20749        &self,
20750        window: &mut Window,
20751        cx: &mut Context<Self>,
20752    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20753        let snapshot = self.snapshot(window, cx);
20754        let buffer = &snapshot.buffer_snapshot();
20755        let start = buffer.anchor_before(0);
20756        let end = buffer.anchor_after(buffer.len());
20757        self.sorted_background_highlights_in_range(start..end, &snapshot, cx.theme())
20758    }
20759
20760    #[cfg(any(test, feature = "test-support"))]
20761    pub fn sorted_background_highlights_in_range(
20762        &self,
20763        search_range: Range<Anchor>,
20764        display_snapshot: &DisplaySnapshot,
20765        theme: &Theme,
20766    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20767        let mut res = self.background_highlights_in_range(search_range, display_snapshot, theme);
20768        res.sort_by(|a, b| {
20769            a.0.start
20770                .cmp(&b.0.start)
20771                .then_with(|| a.0.end.cmp(&b.0.end))
20772                .then_with(|| a.1.cmp(&b.1))
20773        });
20774        res
20775    }
20776
20777    #[cfg(feature = "test-support")]
20778    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
20779        let snapshot = self.buffer().read(cx).snapshot(cx);
20780
20781        let highlights = self
20782            .background_highlights
20783            .get(&HighlightKey::Type(TypeId::of::<
20784                items::BufferSearchHighlights,
20785            >()));
20786
20787        if let Some((_color, ranges)) = highlights {
20788            ranges
20789                .iter()
20790                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
20791                .collect_vec()
20792        } else {
20793            vec![]
20794        }
20795    }
20796
20797    fn document_highlights_for_position<'a>(
20798        &'a self,
20799        position: Anchor,
20800        buffer: &'a MultiBufferSnapshot,
20801    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
20802        let read_highlights = self
20803            .background_highlights
20804            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
20805            .map(|h| &h.1);
20806        let write_highlights = self
20807            .background_highlights
20808            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
20809            .map(|h| &h.1);
20810        let left_position = position.bias_left(buffer);
20811        let right_position = position.bias_right(buffer);
20812        read_highlights
20813            .into_iter()
20814            .chain(write_highlights)
20815            .flat_map(move |ranges| {
20816                let start_ix = match ranges.binary_search_by(|probe| {
20817                    let cmp = probe.end.cmp(&left_position, buffer);
20818                    if cmp.is_ge() {
20819                        Ordering::Greater
20820                    } else {
20821                        Ordering::Less
20822                    }
20823                }) {
20824                    Ok(i) | Err(i) => i,
20825                };
20826
20827                ranges[start_ix..]
20828                    .iter()
20829                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
20830            })
20831    }
20832
20833    pub fn has_background_highlights<T: 'static>(&self) -> bool {
20834        self.background_highlights
20835            .get(&HighlightKey::Type(TypeId::of::<T>()))
20836            .is_some_and(|(_, highlights)| !highlights.is_empty())
20837    }
20838
20839    /// Returns all background highlights for a given range.
20840    ///
20841    /// The order of highlights is not deterministic, do sort the ranges if needed for the logic.
20842    pub fn background_highlights_in_range(
20843        &self,
20844        search_range: Range<Anchor>,
20845        display_snapshot: &DisplaySnapshot,
20846        theme: &Theme,
20847    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20848        let mut results = Vec::new();
20849        for (color_fetcher, ranges) in self.background_highlights.values() {
20850            let color = color_fetcher(theme);
20851            let start_ix = match ranges.binary_search_by(|probe| {
20852                let cmp = probe
20853                    .end
20854                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
20855                if cmp.is_gt() {
20856                    Ordering::Greater
20857                } else {
20858                    Ordering::Less
20859                }
20860            }) {
20861                Ok(i) | Err(i) => i,
20862            };
20863            for range in &ranges[start_ix..] {
20864                if range
20865                    .start
20866                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
20867                    .is_ge()
20868                {
20869                    break;
20870                }
20871
20872                let start = range.start.to_display_point(display_snapshot);
20873                let end = range.end.to_display_point(display_snapshot);
20874                results.push((start..end, color))
20875            }
20876        }
20877        results
20878    }
20879
20880    pub fn gutter_highlights_in_range(
20881        &self,
20882        search_range: Range<Anchor>,
20883        display_snapshot: &DisplaySnapshot,
20884        cx: &App,
20885    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20886        let mut results = Vec::new();
20887        for (color_fetcher, ranges) in self.gutter_highlights.values() {
20888            let color = color_fetcher(cx);
20889            let start_ix = match ranges.binary_search_by(|probe| {
20890                let cmp = probe
20891                    .end
20892                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
20893                if cmp.is_gt() {
20894                    Ordering::Greater
20895                } else {
20896                    Ordering::Less
20897                }
20898            }) {
20899                Ok(i) | Err(i) => i,
20900            };
20901            for range in &ranges[start_ix..] {
20902                if range
20903                    .start
20904                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
20905                    .is_ge()
20906                {
20907                    break;
20908                }
20909
20910                let start = range.start.to_display_point(display_snapshot);
20911                let end = range.end.to_display_point(display_snapshot);
20912                results.push((start..end, color))
20913            }
20914        }
20915        results
20916    }
20917
20918    /// Get the text ranges corresponding to the redaction query
20919    pub fn redacted_ranges(
20920        &self,
20921        search_range: Range<Anchor>,
20922        display_snapshot: &DisplaySnapshot,
20923        cx: &App,
20924    ) -> Vec<Range<DisplayPoint>> {
20925        display_snapshot
20926            .buffer_snapshot()
20927            .redacted_ranges(search_range, |file| {
20928                if let Some(file) = file {
20929                    file.is_private()
20930                        && EditorSettings::get(
20931                            Some(SettingsLocation {
20932                                worktree_id: file.worktree_id(cx),
20933                                path: file.path().as_ref(),
20934                            }),
20935                            cx,
20936                        )
20937                        .redact_private_values
20938                } else {
20939                    false
20940                }
20941            })
20942            .map(|range| {
20943                range.start.to_display_point(display_snapshot)
20944                    ..range.end.to_display_point(display_snapshot)
20945            })
20946            .collect()
20947    }
20948
20949    pub fn highlight_text_key<T: 'static>(
20950        &mut self,
20951        key: usize,
20952        ranges: Vec<Range<Anchor>>,
20953        style: HighlightStyle,
20954        cx: &mut Context<Self>,
20955    ) {
20956        self.display_map.update(cx, |map, _| {
20957            map.highlight_text(
20958                HighlightKey::TypePlus(TypeId::of::<T>(), key),
20959                ranges,
20960                style,
20961            );
20962        });
20963        cx.notify();
20964    }
20965
20966    pub fn highlight_text<T: 'static>(
20967        &mut self,
20968        ranges: Vec<Range<Anchor>>,
20969        style: HighlightStyle,
20970        cx: &mut Context<Self>,
20971    ) {
20972        self.display_map.update(cx, |map, _| {
20973            map.highlight_text(HighlightKey::Type(TypeId::of::<T>()), ranges, style)
20974        });
20975        cx.notify();
20976    }
20977
20978    pub fn text_highlights<'a, T: 'static>(
20979        &'a self,
20980        cx: &'a App,
20981    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
20982        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
20983    }
20984
20985    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
20986        let cleared = self
20987            .display_map
20988            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
20989        if cleared {
20990            cx.notify();
20991        }
20992    }
20993
20994    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
20995        (self.read_only(cx) || self.blink_manager.read(cx).visible())
20996            && self.focus_handle.is_focused(window)
20997    }
20998
20999    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
21000        self.show_cursor_when_unfocused = is_enabled;
21001        cx.notify();
21002    }
21003
21004    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
21005        cx.notify();
21006    }
21007
21008    fn on_debug_session_event(
21009        &mut self,
21010        _session: Entity<Session>,
21011        event: &SessionEvent,
21012        cx: &mut Context<Self>,
21013    ) {
21014        if let SessionEvent::InvalidateInlineValue = event {
21015            self.refresh_inline_values(cx);
21016        }
21017    }
21018
21019    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
21020        let Some(project) = self.project.clone() else {
21021            return;
21022        };
21023
21024        if !self.inline_value_cache.enabled {
21025            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
21026            self.splice_inlays(&inlays, Vec::new(), cx);
21027            return;
21028        }
21029
21030        let current_execution_position = self
21031            .highlighted_rows
21032            .get(&TypeId::of::<ActiveDebugLine>())
21033            .and_then(|lines| lines.last().map(|line| line.range.end));
21034
21035        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
21036            let inline_values = editor
21037                .update(cx, |editor, cx| {
21038                    let Some(current_execution_position) = current_execution_position else {
21039                        return Some(Task::ready(Ok(Vec::new())));
21040                    };
21041
21042                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
21043                        let snapshot = buffer.snapshot(cx);
21044
21045                        let excerpt = snapshot.excerpt_containing(
21046                            current_execution_position..current_execution_position,
21047                        )?;
21048
21049                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
21050                    })?;
21051
21052                    let range =
21053                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
21054
21055                    project.inline_values(buffer, range, cx)
21056                })
21057                .ok()
21058                .flatten()?
21059                .await
21060                .context("refreshing debugger inlays")
21061                .log_err()?;
21062
21063            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
21064
21065            for (buffer_id, inline_value) in inline_values
21066                .into_iter()
21067                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
21068            {
21069                buffer_inline_values
21070                    .entry(buffer_id)
21071                    .or_default()
21072                    .push(inline_value);
21073            }
21074
21075            editor
21076                .update(cx, |editor, cx| {
21077                    let snapshot = editor.buffer.read(cx).snapshot(cx);
21078                    let mut new_inlays = Vec::default();
21079
21080                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
21081                        let buffer_id = buffer_snapshot.remote_id();
21082                        buffer_inline_values
21083                            .get(&buffer_id)
21084                            .into_iter()
21085                            .flatten()
21086                            .for_each(|hint| {
21087                                let inlay = Inlay::debugger(
21088                                    post_inc(&mut editor.next_inlay_id),
21089                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
21090                                    hint.text(),
21091                                );
21092                                if !inlay.text().chars().contains(&'\n') {
21093                                    new_inlays.push(inlay);
21094                                }
21095                            });
21096                    }
21097
21098                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
21099                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
21100
21101                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
21102                })
21103                .ok()?;
21104            Some(())
21105        });
21106    }
21107
21108    fn on_buffer_event(
21109        &mut self,
21110        multibuffer: &Entity<MultiBuffer>,
21111        event: &multi_buffer::Event,
21112        window: &mut Window,
21113        cx: &mut Context<Self>,
21114    ) {
21115        match event {
21116            multi_buffer::Event::Edited { edited_buffer } => {
21117                self.scrollbar_marker_state.dirty = true;
21118                self.active_indent_guides_state.dirty = true;
21119                self.refresh_active_diagnostics(cx);
21120                self.refresh_code_actions(window, cx);
21121                self.refresh_selected_text_highlights(true, window, cx);
21122                self.refresh_single_line_folds(window, cx);
21123                self.refresh_matching_bracket_highlights(window, cx);
21124                if self.has_active_edit_prediction() {
21125                    self.update_visible_edit_prediction(window, cx);
21126                }
21127
21128                if let Some(buffer) = edited_buffer {
21129                    if buffer.read(cx).file().is_none() {
21130                        cx.emit(EditorEvent::TitleChanged);
21131                    }
21132
21133                    if self.project.is_some() {
21134                        let buffer_id = buffer.read(cx).remote_id();
21135                        self.register_buffer(buffer_id, cx);
21136                        self.update_lsp_data(Some(buffer_id), window, cx);
21137                        self.refresh_inlay_hints(
21138                            InlayHintRefreshReason::BufferEdited(buffer_id),
21139                            cx,
21140                        );
21141                    }
21142                }
21143
21144                cx.emit(EditorEvent::BufferEdited);
21145                cx.emit(SearchEvent::MatchesInvalidated);
21146
21147                let Some(project) = &self.project else { return };
21148                let (telemetry, is_via_ssh) = {
21149                    let project = project.read(cx);
21150                    let telemetry = project.client().telemetry().clone();
21151                    let is_via_ssh = project.is_via_remote_server();
21152                    (telemetry, is_via_ssh)
21153                };
21154                telemetry.log_edit_event("editor", is_via_ssh);
21155            }
21156            multi_buffer::Event::ExcerptsAdded {
21157                buffer,
21158                predecessor,
21159                excerpts,
21160            } => {
21161                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21162                let buffer_id = buffer.read(cx).remote_id();
21163                if self.buffer.read(cx).diff_for(buffer_id).is_none()
21164                    && let Some(project) = &self.project
21165                {
21166                    update_uncommitted_diff_for_buffer(
21167                        cx.entity(),
21168                        project,
21169                        [buffer.clone()],
21170                        self.buffer.clone(),
21171                        cx,
21172                    )
21173                    .detach();
21174                }
21175                self.update_lsp_data(Some(buffer_id), window, cx);
21176                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
21177                cx.emit(EditorEvent::ExcerptsAdded {
21178                    buffer: buffer.clone(),
21179                    predecessor: *predecessor,
21180                    excerpts: excerpts.clone(),
21181                });
21182            }
21183            multi_buffer::Event::ExcerptsRemoved {
21184                ids,
21185                removed_buffer_ids,
21186            } => {
21187                if let Some(inlay_hints) = &mut self.inlay_hints {
21188                    inlay_hints.remove_inlay_chunk_data(removed_buffer_ids);
21189                }
21190                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
21191                for buffer_id in removed_buffer_ids {
21192                    self.registered_buffers.remove(buffer_id);
21193                }
21194                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
21195                cx.emit(EditorEvent::ExcerptsRemoved {
21196                    ids: ids.clone(),
21197                    removed_buffer_ids: removed_buffer_ids.clone(),
21198                });
21199            }
21200            multi_buffer::Event::ExcerptsEdited {
21201                excerpt_ids,
21202                buffer_ids,
21203            } => {
21204                self.display_map.update(cx, |map, cx| {
21205                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
21206                });
21207                cx.emit(EditorEvent::ExcerptsEdited {
21208                    ids: excerpt_ids.clone(),
21209                });
21210            }
21211            multi_buffer::Event::ExcerptsExpanded { ids } => {
21212                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
21213                self.refresh_document_highlights(cx);
21214                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
21215            }
21216            multi_buffer::Event::Reparsed(buffer_id) => {
21217                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21218                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
21219
21220                cx.emit(EditorEvent::Reparsed(*buffer_id));
21221            }
21222            multi_buffer::Event::DiffHunksToggled => {
21223                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21224            }
21225            multi_buffer::Event::LanguageChanged(buffer_id) => {
21226                self.registered_buffers.remove(&buffer_id);
21227                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
21228                cx.emit(EditorEvent::Reparsed(*buffer_id));
21229                cx.notify();
21230            }
21231            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
21232            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
21233            multi_buffer::Event::FileHandleChanged
21234            | multi_buffer::Event::Reloaded
21235            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
21236            multi_buffer::Event::DiagnosticsUpdated => {
21237                self.update_diagnostics_state(window, cx);
21238            }
21239            _ => {}
21240        };
21241    }
21242
21243    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
21244        if !self.diagnostics_enabled() {
21245            return;
21246        }
21247        self.refresh_active_diagnostics(cx);
21248        self.refresh_inline_diagnostics(true, window, cx);
21249        self.scrollbar_marker_state.dirty = true;
21250        cx.notify();
21251    }
21252
21253    pub fn start_temporary_diff_override(&mut self) {
21254        self.load_diff_task.take();
21255        self.temporary_diff_override = true;
21256    }
21257
21258    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
21259        self.temporary_diff_override = false;
21260        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
21261        self.buffer.update(cx, |buffer, cx| {
21262            buffer.set_all_diff_hunks_collapsed(cx);
21263        });
21264
21265        if let Some(project) = self.project.clone() {
21266            self.load_diff_task = Some(
21267                update_uncommitted_diff_for_buffer(
21268                    cx.entity(),
21269                    &project,
21270                    self.buffer.read(cx).all_buffers(),
21271                    self.buffer.clone(),
21272                    cx,
21273                )
21274                .shared(),
21275            );
21276        }
21277    }
21278
21279    fn on_display_map_changed(
21280        &mut self,
21281        _: Entity<DisplayMap>,
21282        _: &mut Window,
21283        cx: &mut Context<Self>,
21284    ) {
21285        cx.notify();
21286    }
21287
21288    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21289        if self.diagnostics_enabled() {
21290            let new_severity = EditorSettings::get_global(cx)
21291                .diagnostics_max_severity
21292                .unwrap_or(DiagnosticSeverity::Hint);
21293            self.set_max_diagnostics_severity(new_severity, cx);
21294        }
21295        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21296        self.update_edit_prediction_settings(cx);
21297        self.refresh_edit_prediction(true, false, window, cx);
21298        self.refresh_inline_values(cx);
21299        self.refresh_inlay_hints(
21300            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
21301                self.selections.newest_anchor().head(),
21302                &self.buffer.read(cx).snapshot(cx),
21303                cx,
21304            )),
21305            cx,
21306        );
21307
21308        let old_cursor_shape = self.cursor_shape;
21309        let old_show_breadcrumbs = self.show_breadcrumbs;
21310
21311        {
21312            let editor_settings = EditorSettings::get_global(cx);
21313            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
21314            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
21315            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
21316            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
21317        }
21318
21319        if old_cursor_shape != self.cursor_shape {
21320            cx.emit(EditorEvent::CursorShapeChanged);
21321        }
21322
21323        if old_show_breadcrumbs != self.show_breadcrumbs {
21324            cx.emit(EditorEvent::BreadcrumbsChanged);
21325        }
21326
21327        let project_settings = ProjectSettings::get_global(cx);
21328        self.buffer_serialization = self
21329            .should_serialize_buffer()
21330            .then(|| BufferSerialization::new(project_settings.session.restore_unsaved_buffers));
21331
21332        if self.mode.is_full() {
21333            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
21334            let inline_blame_enabled = project_settings.git.inline_blame.enabled;
21335            if self.show_inline_diagnostics != show_inline_diagnostics {
21336                self.show_inline_diagnostics = show_inline_diagnostics;
21337                self.refresh_inline_diagnostics(false, window, cx);
21338            }
21339
21340            if self.git_blame_inline_enabled != inline_blame_enabled {
21341                self.toggle_git_blame_inline_internal(false, window, cx);
21342            }
21343
21344            let minimap_settings = EditorSettings::get_global(cx).minimap;
21345            if self.minimap_visibility != MinimapVisibility::Disabled {
21346                if self.minimap_visibility.settings_visibility()
21347                    != minimap_settings.minimap_enabled()
21348                {
21349                    self.set_minimap_visibility(
21350                        MinimapVisibility::for_mode(self.mode(), cx),
21351                        window,
21352                        cx,
21353                    );
21354                } else if let Some(minimap_entity) = self.minimap.as_ref() {
21355                    minimap_entity.update(cx, |minimap_editor, cx| {
21356                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
21357                    })
21358                }
21359            }
21360        }
21361
21362        if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
21363            colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
21364        }) {
21365            if !inlay_splice.is_empty() {
21366                self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
21367            }
21368            self.refresh_colors_for_visible_range(None, window, cx);
21369        }
21370
21371        cx.notify();
21372    }
21373
21374    pub fn set_searchable(&mut self, searchable: bool) {
21375        self.searchable = searchable;
21376    }
21377
21378    pub fn searchable(&self) -> bool {
21379        self.searchable
21380    }
21381
21382    pub fn open_excerpts_in_split(
21383        &mut self,
21384        _: &OpenExcerptsSplit,
21385        window: &mut Window,
21386        cx: &mut Context<Self>,
21387    ) {
21388        self.open_excerpts_common(None, true, window, cx)
21389    }
21390
21391    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
21392        self.open_excerpts_common(None, false, window, cx)
21393    }
21394
21395    fn open_excerpts_common(
21396        &mut self,
21397        jump_data: Option<JumpData>,
21398        split: bool,
21399        window: &mut Window,
21400        cx: &mut Context<Self>,
21401    ) {
21402        let Some(workspace) = self.workspace() else {
21403            cx.propagate();
21404            return;
21405        };
21406
21407        if self.buffer.read(cx).is_singleton() {
21408            cx.propagate();
21409            return;
21410        }
21411
21412        let mut new_selections_by_buffer = HashMap::default();
21413        match &jump_data {
21414            Some(JumpData::MultiBufferPoint {
21415                excerpt_id,
21416                position,
21417                anchor,
21418                line_offset_from_top,
21419            }) => {
21420                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
21421                if let Some(buffer) = multi_buffer_snapshot
21422                    .buffer_id_for_excerpt(*excerpt_id)
21423                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
21424                {
21425                    let buffer_snapshot = buffer.read(cx).snapshot();
21426                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
21427                        language::ToPoint::to_point(anchor, &buffer_snapshot)
21428                    } else {
21429                        buffer_snapshot.clip_point(*position, Bias::Left)
21430                    };
21431                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
21432                    new_selections_by_buffer.insert(
21433                        buffer,
21434                        (
21435                            vec![jump_to_offset..jump_to_offset],
21436                            Some(*line_offset_from_top),
21437                        ),
21438                    );
21439                }
21440            }
21441            Some(JumpData::MultiBufferRow {
21442                row,
21443                line_offset_from_top,
21444            }) => {
21445                let point = MultiBufferPoint::new(row.0, 0);
21446                if let Some((buffer, buffer_point, _)) =
21447                    self.buffer.read(cx).point_to_buffer_point(point, cx)
21448                {
21449                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
21450                    new_selections_by_buffer
21451                        .entry(buffer)
21452                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
21453                        .0
21454                        .push(buffer_offset..buffer_offset)
21455                }
21456            }
21457            None => {
21458                let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
21459                let multi_buffer = self.buffer.read(cx);
21460                for selection in selections {
21461                    for (snapshot, range, _, anchor) in multi_buffer
21462                        .snapshot(cx)
21463                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
21464                    {
21465                        if let Some(anchor) = anchor {
21466                            let Some(buffer_handle) = multi_buffer.buffer_for_anchor(anchor, cx)
21467                            else {
21468                                continue;
21469                            };
21470                            let offset = text::ToOffset::to_offset(
21471                                &anchor.text_anchor,
21472                                &buffer_handle.read(cx).snapshot(),
21473                            );
21474                            let range = offset..offset;
21475                            new_selections_by_buffer
21476                                .entry(buffer_handle)
21477                                .or_insert((Vec::new(), None))
21478                                .0
21479                                .push(range)
21480                        } else {
21481                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
21482                            else {
21483                                continue;
21484                            };
21485                            new_selections_by_buffer
21486                                .entry(buffer_handle)
21487                                .or_insert((Vec::new(), None))
21488                                .0
21489                                .push(range)
21490                        }
21491                    }
21492                }
21493            }
21494        }
21495
21496        new_selections_by_buffer
21497            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
21498
21499        if new_selections_by_buffer.is_empty() {
21500            return;
21501        }
21502
21503        // We defer the pane interaction because we ourselves are a workspace item
21504        // and activating a new item causes the pane to call a method on us reentrantly,
21505        // which panics if we're on the stack.
21506        window.defer(cx, move |window, cx| {
21507            workspace.update(cx, |workspace, cx| {
21508                let pane = if split {
21509                    workspace.adjacent_pane(window, cx)
21510                } else {
21511                    workspace.active_pane().clone()
21512                };
21513
21514                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
21515                    let editor = buffer
21516                        .read(cx)
21517                        .file()
21518                        .is_none()
21519                        .then(|| {
21520                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
21521                            // so `workspace.open_project_item` will never find them, always opening a new editor.
21522                            // Instead, we try to activate the existing editor in the pane first.
21523                            let (editor, pane_item_index) =
21524                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
21525                                    let editor = item.downcast::<Editor>()?;
21526                                    let singleton_buffer =
21527                                        editor.read(cx).buffer().read(cx).as_singleton()?;
21528                                    if singleton_buffer == buffer {
21529                                        Some((editor, i))
21530                                    } else {
21531                                        None
21532                                    }
21533                                })?;
21534                            pane.update(cx, |pane, cx| {
21535                                pane.activate_item(pane_item_index, true, true, window, cx)
21536                            });
21537                            Some(editor)
21538                        })
21539                        .flatten()
21540                        .unwrap_or_else(|| {
21541                            workspace.open_project_item::<Self>(
21542                                pane.clone(),
21543                                buffer,
21544                                true,
21545                                true,
21546                                window,
21547                                cx,
21548                            )
21549                        });
21550
21551                    editor.update(cx, |editor, cx| {
21552                        let autoscroll = match scroll_offset {
21553                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
21554                            None => Autoscroll::newest(),
21555                        };
21556                        let nav_history = editor.nav_history.take();
21557                        editor.change_selections(
21558                            SelectionEffects::scroll(autoscroll),
21559                            window,
21560                            cx,
21561                            |s| {
21562                                s.select_ranges(ranges);
21563                            },
21564                        );
21565                        editor.nav_history = nav_history;
21566                    });
21567                }
21568            })
21569        });
21570    }
21571
21572    // For now, don't allow opening excerpts in buffers that aren't backed by
21573    // regular project files.
21574    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
21575        file.is_none_or(|file| project::File::from_dyn(Some(file)).is_some())
21576    }
21577
21578    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
21579        let snapshot = self.buffer.read(cx).read(cx);
21580        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
21581        Some(
21582            ranges
21583                .iter()
21584                .map(move |range| {
21585                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
21586                })
21587                .collect(),
21588        )
21589    }
21590
21591    fn selection_replacement_ranges(
21592        &self,
21593        range: Range<OffsetUtf16>,
21594        cx: &mut App,
21595    ) -> Vec<Range<OffsetUtf16>> {
21596        let selections = self
21597            .selections
21598            .all::<OffsetUtf16>(&self.display_snapshot(cx));
21599        let newest_selection = selections
21600            .iter()
21601            .max_by_key(|selection| selection.id)
21602            .unwrap();
21603        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
21604        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
21605        let snapshot = self.buffer.read(cx).read(cx);
21606        selections
21607            .into_iter()
21608            .map(|mut selection| {
21609                selection.start.0 =
21610                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
21611                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
21612                snapshot.clip_offset_utf16(selection.start, Bias::Left)
21613                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
21614            })
21615            .collect()
21616    }
21617
21618    fn report_editor_event(
21619        &self,
21620        reported_event: ReportEditorEvent,
21621        file_extension: Option<String>,
21622        cx: &App,
21623    ) {
21624        if cfg!(any(test, feature = "test-support")) {
21625            return;
21626        }
21627
21628        let Some(project) = &self.project else { return };
21629
21630        // If None, we are in a file without an extension
21631        let file = self
21632            .buffer
21633            .read(cx)
21634            .as_singleton()
21635            .and_then(|b| b.read(cx).file());
21636        let file_extension = file_extension.or(file
21637            .as_ref()
21638            .and_then(|file| Path::new(file.file_name(cx)).extension())
21639            .and_then(|e| e.to_str())
21640            .map(|a| a.to_string()));
21641
21642        let vim_mode = vim_flavor(cx).is_some();
21643
21644        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
21645        let copilot_enabled = edit_predictions_provider
21646            == language::language_settings::EditPredictionProvider::Copilot;
21647        let copilot_enabled_for_language = self
21648            .buffer
21649            .read(cx)
21650            .language_settings(cx)
21651            .show_edit_predictions;
21652
21653        let project = project.read(cx);
21654        let event_type = reported_event.event_type();
21655
21656        if let ReportEditorEvent::Saved { auto_saved } = reported_event {
21657            telemetry::event!(
21658                event_type,
21659                type = if auto_saved {"autosave"} else {"manual"},
21660                file_extension,
21661                vim_mode,
21662                copilot_enabled,
21663                copilot_enabled_for_language,
21664                edit_predictions_provider,
21665                is_via_ssh = project.is_via_remote_server(),
21666            );
21667        } else {
21668            telemetry::event!(
21669                event_type,
21670                file_extension,
21671                vim_mode,
21672                copilot_enabled,
21673                copilot_enabled_for_language,
21674                edit_predictions_provider,
21675                is_via_ssh = project.is_via_remote_server(),
21676            );
21677        };
21678    }
21679
21680    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
21681    /// with each line being an array of {text, highlight} objects.
21682    fn copy_highlight_json(
21683        &mut self,
21684        _: &CopyHighlightJson,
21685        window: &mut Window,
21686        cx: &mut Context<Self>,
21687    ) {
21688        #[derive(Serialize)]
21689        struct Chunk<'a> {
21690            text: String,
21691            highlight: Option<&'a str>,
21692        }
21693
21694        let snapshot = self.buffer.read(cx).snapshot(cx);
21695        let range = self
21696            .selected_text_range(false, window, cx)
21697            .and_then(|selection| {
21698                if selection.range.is_empty() {
21699                    None
21700                } else {
21701                    Some(
21702                        snapshot.offset_utf16_to_offset(OffsetUtf16(selection.range.start))
21703                            ..snapshot.offset_utf16_to_offset(OffsetUtf16(selection.range.end)),
21704                    )
21705                }
21706            })
21707            .unwrap_or_else(|| 0..snapshot.len());
21708
21709        let chunks = snapshot.chunks(range, true);
21710        let mut lines = Vec::new();
21711        let mut line: VecDeque<Chunk> = VecDeque::new();
21712
21713        let Some(style) = self.style.as_ref() else {
21714            return;
21715        };
21716
21717        for chunk in chunks {
21718            let highlight = chunk
21719                .syntax_highlight_id
21720                .and_then(|id| id.name(&style.syntax));
21721            let mut chunk_lines = chunk.text.split('\n').peekable();
21722            while let Some(text) = chunk_lines.next() {
21723                let mut merged_with_last_token = false;
21724                if let Some(last_token) = line.back_mut()
21725                    && last_token.highlight == highlight
21726                {
21727                    last_token.text.push_str(text);
21728                    merged_with_last_token = true;
21729                }
21730
21731                if !merged_with_last_token {
21732                    line.push_back(Chunk {
21733                        text: text.into(),
21734                        highlight,
21735                    });
21736                }
21737
21738                if chunk_lines.peek().is_some() {
21739                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
21740                        line.pop_front();
21741                    }
21742                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
21743                        line.pop_back();
21744                    }
21745
21746                    lines.push(mem::take(&mut line));
21747                }
21748            }
21749        }
21750
21751        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
21752            return;
21753        };
21754        cx.write_to_clipboard(ClipboardItem::new_string(lines));
21755    }
21756
21757    pub fn open_context_menu(
21758        &mut self,
21759        _: &OpenContextMenu,
21760        window: &mut Window,
21761        cx: &mut Context<Self>,
21762    ) {
21763        self.request_autoscroll(Autoscroll::newest(), cx);
21764        let position = self
21765            .selections
21766            .newest_display(&self.display_snapshot(cx))
21767            .start;
21768        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
21769    }
21770
21771    pub fn replay_insert_event(
21772        &mut self,
21773        text: &str,
21774        relative_utf16_range: Option<Range<isize>>,
21775        window: &mut Window,
21776        cx: &mut Context<Self>,
21777    ) {
21778        if !self.input_enabled {
21779            cx.emit(EditorEvent::InputIgnored { text: text.into() });
21780            return;
21781        }
21782        if let Some(relative_utf16_range) = relative_utf16_range {
21783            let selections = self
21784                .selections
21785                .all::<OffsetUtf16>(&self.display_snapshot(cx));
21786            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21787                let new_ranges = selections.into_iter().map(|range| {
21788                    let start = OffsetUtf16(
21789                        range
21790                            .head()
21791                            .0
21792                            .saturating_add_signed(relative_utf16_range.start),
21793                    );
21794                    let end = OffsetUtf16(
21795                        range
21796                            .head()
21797                            .0
21798                            .saturating_add_signed(relative_utf16_range.end),
21799                    );
21800                    start..end
21801                });
21802                s.select_ranges(new_ranges);
21803            });
21804        }
21805
21806        self.handle_input(text, window, cx);
21807    }
21808
21809    pub fn is_focused(&self, window: &Window) -> bool {
21810        self.focus_handle.is_focused(window)
21811    }
21812
21813    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21814        cx.emit(EditorEvent::Focused);
21815
21816        if let Some(descendant) = self
21817            .last_focused_descendant
21818            .take()
21819            .and_then(|descendant| descendant.upgrade())
21820        {
21821            window.focus(&descendant);
21822        } else {
21823            if let Some(blame) = self.blame.as_ref() {
21824                blame.update(cx, GitBlame::focus)
21825            }
21826
21827            self.blink_manager.update(cx, BlinkManager::enable);
21828            self.show_cursor_names(window, cx);
21829            self.buffer.update(cx, |buffer, cx| {
21830                buffer.finalize_last_transaction(cx);
21831                if self.leader_id.is_none() {
21832                    buffer.set_active_selections(
21833                        &self.selections.disjoint_anchors_arc(),
21834                        self.selections.line_mode(),
21835                        self.cursor_shape,
21836                        cx,
21837                    );
21838                }
21839            });
21840        }
21841    }
21842
21843    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
21844        cx.emit(EditorEvent::FocusedIn)
21845    }
21846
21847    fn handle_focus_out(
21848        &mut self,
21849        event: FocusOutEvent,
21850        _window: &mut Window,
21851        cx: &mut Context<Self>,
21852    ) {
21853        if event.blurred != self.focus_handle {
21854            self.last_focused_descendant = Some(event.blurred);
21855        }
21856        self.selection_drag_state = SelectionDragState::None;
21857        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
21858    }
21859
21860    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21861        self.blink_manager.update(cx, BlinkManager::disable);
21862        self.buffer
21863            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
21864
21865        if let Some(blame) = self.blame.as_ref() {
21866            blame.update(cx, GitBlame::blur)
21867        }
21868        if !self.hover_state.focused(window, cx) {
21869            hide_hover(self, cx);
21870        }
21871        if !self
21872            .context_menu
21873            .borrow()
21874            .as_ref()
21875            .is_some_and(|context_menu| context_menu.focused(window, cx))
21876        {
21877            self.hide_context_menu(window, cx);
21878        }
21879        self.take_active_edit_prediction(cx);
21880        cx.emit(EditorEvent::Blurred);
21881        cx.notify();
21882    }
21883
21884    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21885        let mut pending: String = window
21886            .pending_input_keystrokes()
21887            .into_iter()
21888            .flatten()
21889            .filter_map(|keystroke| {
21890                if keystroke.modifiers.is_subset_of(&Modifiers::shift()) {
21891                    keystroke.key_char.clone()
21892                } else {
21893                    None
21894                }
21895            })
21896            .collect();
21897
21898        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
21899            pending = "".to_string();
21900        }
21901
21902        let existing_pending = self
21903            .text_highlights::<PendingInput>(cx)
21904            .map(|(_, ranges)| ranges.to_vec());
21905        if existing_pending.is_none() && pending.is_empty() {
21906            return;
21907        }
21908        let transaction =
21909            self.transact(window, cx, |this, window, cx| {
21910                let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
21911                let edits = selections
21912                    .iter()
21913                    .map(|selection| (selection.end..selection.end, pending.clone()));
21914                this.edit(edits, cx);
21915                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21916                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
21917                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
21918                    }));
21919                });
21920                if let Some(existing_ranges) = existing_pending {
21921                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
21922                    this.edit(edits, cx);
21923                }
21924            });
21925
21926        let snapshot = self.snapshot(window, cx);
21927        let ranges = self
21928            .selections
21929            .all::<usize>(&snapshot.display_snapshot)
21930            .into_iter()
21931            .map(|selection| {
21932                snapshot.buffer_snapshot().anchor_after(selection.end)
21933                    ..snapshot
21934                        .buffer_snapshot()
21935                        .anchor_before(selection.end + pending.len())
21936            })
21937            .collect();
21938
21939        if pending.is_empty() {
21940            self.clear_highlights::<PendingInput>(cx);
21941        } else {
21942            self.highlight_text::<PendingInput>(
21943                ranges,
21944                HighlightStyle {
21945                    underline: Some(UnderlineStyle {
21946                        thickness: px(1.),
21947                        color: None,
21948                        wavy: false,
21949                    }),
21950                    ..Default::default()
21951                },
21952                cx,
21953            );
21954        }
21955
21956        self.ime_transaction = self.ime_transaction.or(transaction);
21957        if let Some(transaction) = self.ime_transaction {
21958            self.buffer.update(cx, |buffer, cx| {
21959                buffer.group_until_transaction(transaction, cx);
21960            });
21961        }
21962
21963        if self.text_highlights::<PendingInput>(cx).is_none() {
21964            self.ime_transaction.take();
21965        }
21966    }
21967
21968    pub fn register_action_renderer(
21969        &mut self,
21970        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
21971    ) -> Subscription {
21972        let id = self.next_editor_action_id.post_inc();
21973        self.editor_actions
21974            .borrow_mut()
21975            .insert(id, Box::new(listener));
21976
21977        let editor_actions = self.editor_actions.clone();
21978        Subscription::new(move || {
21979            editor_actions.borrow_mut().remove(&id);
21980        })
21981    }
21982
21983    pub fn register_action<A: Action>(
21984        &mut self,
21985        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
21986    ) -> Subscription {
21987        let id = self.next_editor_action_id.post_inc();
21988        let listener = Arc::new(listener);
21989        self.editor_actions.borrow_mut().insert(
21990            id,
21991            Box::new(move |_, window, _| {
21992                let listener = listener.clone();
21993                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
21994                    let action = action.downcast_ref().unwrap();
21995                    if phase == DispatchPhase::Bubble {
21996                        listener(action, window, cx)
21997                    }
21998                })
21999            }),
22000        );
22001
22002        let editor_actions = self.editor_actions.clone();
22003        Subscription::new(move || {
22004            editor_actions.borrow_mut().remove(&id);
22005        })
22006    }
22007
22008    pub fn file_header_size(&self) -> u32 {
22009        FILE_HEADER_HEIGHT
22010    }
22011
22012    pub fn restore(
22013        &mut self,
22014        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
22015        window: &mut Window,
22016        cx: &mut Context<Self>,
22017    ) {
22018        let workspace = self.workspace();
22019        let project = self.project();
22020        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
22021            let mut tasks = Vec::new();
22022            for (buffer_id, changes) in revert_changes {
22023                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
22024                    buffer.update(cx, |buffer, cx| {
22025                        buffer.edit(
22026                            changes
22027                                .into_iter()
22028                                .map(|(range, text)| (range, text.to_string())),
22029                            None,
22030                            cx,
22031                        );
22032                    });
22033
22034                    if let Some(project) =
22035                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
22036                    {
22037                        project.update(cx, |project, cx| {
22038                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
22039                        })
22040                    }
22041                }
22042            }
22043            tasks
22044        });
22045        cx.spawn_in(window, async move |_, cx| {
22046            for (buffer, task) in save_tasks {
22047                let result = task.await;
22048                if result.is_err() {
22049                    let Some(path) = buffer
22050                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
22051                        .ok()
22052                    else {
22053                        continue;
22054                    };
22055                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
22056                        let Some(task) = cx
22057                            .update_window_entity(workspace, |workspace, window, cx| {
22058                                workspace
22059                                    .open_path_preview(path, None, false, false, false, window, cx)
22060                            })
22061                            .ok()
22062                        else {
22063                            continue;
22064                        };
22065                        task.await.log_err();
22066                    }
22067                }
22068            }
22069        })
22070        .detach();
22071        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
22072            selections.refresh()
22073        });
22074    }
22075
22076    pub fn to_pixel_point(
22077        &self,
22078        source: multi_buffer::Anchor,
22079        editor_snapshot: &EditorSnapshot,
22080        window: &mut Window,
22081    ) -> Option<gpui::Point<Pixels>> {
22082        let source_point = source.to_display_point(editor_snapshot);
22083        self.display_to_pixel_point(source_point, editor_snapshot, window)
22084    }
22085
22086    pub fn display_to_pixel_point(
22087        &self,
22088        source: DisplayPoint,
22089        editor_snapshot: &EditorSnapshot,
22090        window: &mut Window,
22091    ) -> Option<gpui::Point<Pixels>> {
22092        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
22093        let text_layout_details = self.text_layout_details(window);
22094        let scroll_top = text_layout_details
22095            .scroll_anchor
22096            .scroll_position(editor_snapshot)
22097            .y;
22098
22099        if source.row().as_f64() < scroll_top.floor() {
22100            return None;
22101        }
22102        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
22103        let source_y = line_height * (source.row().as_f64() - scroll_top) as f32;
22104        Some(gpui::Point::new(source_x, source_y))
22105    }
22106
22107    pub fn has_visible_completions_menu(&self) -> bool {
22108        !self.edit_prediction_preview_is_active()
22109            && self.context_menu.borrow().as_ref().is_some_and(|menu| {
22110                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
22111            })
22112    }
22113
22114    pub fn register_addon<T: Addon>(&mut self, instance: T) {
22115        if self.mode.is_minimap() {
22116            return;
22117        }
22118        self.addons
22119            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
22120    }
22121
22122    pub fn unregister_addon<T: Addon>(&mut self) {
22123        self.addons.remove(&std::any::TypeId::of::<T>());
22124    }
22125
22126    pub fn addon<T: Addon>(&self) -> Option<&T> {
22127        let type_id = std::any::TypeId::of::<T>();
22128        self.addons
22129            .get(&type_id)
22130            .and_then(|item| item.to_any().downcast_ref::<T>())
22131    }
22132
22133    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
22134        let type_id = std::any::TypeId::of::<T>();
22135        self.addons
22136            .get_mut(&type_id)
22137            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
22138    }
22139
22140    fn character_dimensions(&self, window: &mut Window) -> CharacterDimensions {
22141        let text_layout_details = self.text_layout_details(window);
22142        let style = &text_layout_details.editor_style;
22143        let font_id = window.text_system().resolve_font(&style.text.font());
22144        let font_size = style.text.font_size.to_pixels(window.rem_size());
22145        let line_height = style.text.line_height_in_pixels(window.rem_size());
22146        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
22147        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
22148
22149        CharacterDimensions {
22150            em_width,
22151            em_advance,
22152            line_height,
22153        }
22154    }
22155
22156    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
22157        self.load_diff_task.clone()
22158    }
22159
22160    fn read_metadata_from_db(
22161        &mut self,
22162        item_id: u64,
22163        workspace_id: WorkspaceId,
22164        window: &mut Window,
22165        cx: &mut Context<Editor>,
22166    ) {
22167        if self.buffer_kind(cx) == ItemBufferKind::Singleton
22168            && !self.mode.is_minimap()
22169            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
22170        {
22171            let buffer_snapshot = OnceCell::new();
22172
22173            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err()
22174                && !folds.is_empty()
22175            {
22176                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
22177                self.fold_ranges(
22178                    folds
22179                        .into_iter()
22180                        .map(|(start, end)| {
22181                            snapshot.clip_offset(start, Bias::Left)
22182                                ..snapshot.clip_offset(end, Bias::Right)
22183                        })
22184                        .collect(),
22185                    false,
22186                    window,
22187                    cx,
22188                );
22189            }
22190
22191            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err()
22192                && !selections.is_empty()
22193            {
22194                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
22195                // skip adding the initial selection to selection history
22196                self.selection_history.mode = SelectionHistoryMode::Skipping;
22197                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
22198                    s.select_ranges(selections.into_iter().map(|(start, end)| {
22199                        snapshot.clip_offset(start, Bias::Left)
22200                            ..snapshot.clip_offset(end, Bias::Right)
22201                    }));
22202                });
22203                self.selection_history.mode = SelectionHistoryMode::Normal;
22204            };
22205        }
22206
22207        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
22208    }
22209
22210    fn update_lsp_data(
22211        &mut self,
22212        for_buffer: Option<BufferId>,
22213        window: &mut Window,
22214        cx: &mut Context<'_, Self>,
22215    ) {
22216        self.pull_diagnostics(for_buffer, window, cx);
22217        self.refresh_colors_for_visible_range(for_buffer, window, cx);
22218    }
22219
22220    fn register_visible_buffers(&mut self, cx: &mut Context<Self>) {
22221        if self.ignore_lsp_data() {
22222            return;
22223        }
22224        for (_, (visible_buffer, _, _)) in self.visible_excerpts(cx) {
22225            self.register_buffer(visible_buffer.read(cx).remote_id(), cx);
22226        }
22227    }
22228
22229    fn register_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
22230        if self.ignore_lsp_data() {
22231            return;
22232        }
22233
22234        if !self.registered_buffers.contains_key(&buffer_id)
22235            && let Some(project) = self.project.as_ref()
22236        {
22237            if let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) {
22238                project.update(cx, |project, cx| {
22239                    self.registered_buffers.insert(
22240                        buffer_id,
22241                        project.register_buffer_with_language_servers(&buffer, cx),
22242                    );
22243                });
22244            } else {
22245                self.registered_buffers.remove(&buffer_id);
22246            }
22247        }
22248    }
22249
22250    fn ignore_lsp_data(&self) -> bool {
22251        // `ActiveDiagnostic::All` is a special mode where editor's diagnostics are managed by the external view,
22252        // skip any LSP updates for it.
22253        self.active_diagnostics == ActiveDiagnostic::All || !self.mode().is_full()
22254    }
22255}
22256
22257fn edit_for_markdown_paste<'a>(
22258    buffer: &MultiBufferSnapshot,
22259    range: Range<usize>,
22260    to_insert: &'a str,
22261    url: Option<url::Url>,
22262) -> (Range<usize>, Cow<'a, str>) {
22263    if url.is_none() {
22264        return (range, Cow::Borrowed(to_insert));
22265    };
22266
22267    let old_text = buffer.text_for_range(range.clone()).collect::<String>();
22268
22269    let new_text = if range.is_empty() || url::Url::parse(&old_text).is_ok() {
22270        Cow::Borrowed(to_insert)
22271    } else {
22272        Cow::Owned(format!("[{old_text}]({to_insert})"))
22273    };
22274    (range, new_text)
22275}
22276
22277#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
22278pub enum VimFlavor {
22279    Vim,
22280    Helix,
22281}
22282
22283pub fn vim_flavor(cx: &App) -> Option<VimFlavor> {
22284    if vim_mode_setting::HelixModeSetting::try_get(cx)
22285        .map(|helix_mode| helix_mode.0)
22286        .unwrap_or(false)
22287    {
22288        Some(VimFlavor::Helix)
22289    } else if vim_mode_setting::VimModeSetting::try_get(cx)
22290        .map(|vim_mode| vim_mode.0)
22291        .unwrap_or(false)
22292    {
22293        Some(VimFlavor::Vim)
22294    } else {
22295        None // neither vim nor helix mode
22296    }
22297}
22298
22299fn process_completion_for_edit(
22300    completion: &Completion,
22301    intent: CompletionIntent,
22302    buffer: &Entity<Buffer>,
22303    cursor_position: &text::Anchor,
22304    cx: &mut Context<Editor>,
22305) -> CompletionEdit {
22306    let buffer = buffer.read(cx);
22307    let buffer_snapshot = buffer.snapshot();
22308    let (snippet, new_text) = if completion.is_snippet() {
22309        let mut snippet_source = completion.new_text.clone();
22310        // Workaround for typescript language server issues so that methods don't expand within
22311        // strings and functions with type expressions. The previous point is used because the query
22312        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
22313        let previous_point = text::ToPoint::to_point(cursor_position, &buffer_snapshot);
22314        let previous_point = if previous_point.column > 0 {
22315            cursor_position.to_previous_offset(&buffer_snapshot)
22316        } else {
22317            cursor_position.to_offset(&buffer_snapshot)
22318        };
22319        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point)
22320            && scope.prefers_label_for_snippet_in_completion()
22321            && let Some(label) = completion.label()
22322            && matches!(
22323                completion.kind(),
22324                Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
22325            )
22326        {
22327            snippet_source = label;
22328        }
22329        match Snippet::parse(&snippet_source).log_err() {
22330            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
22331            None => (None, completion.new_text.clone()),
22332        }
22333    } else {
22334        (None, completion.new_text.clone())
22335    };
22336
22337    let mut range_to_replace = {
22338        let replace_range = &completion.replace_range;
22339        if let CompletionSource::Lsp {
22340            insert_range: Some(insert_range),
22341            ..
22342        } = &completion.source
22343        {
22344            debug_assert_eq!(
22345                insert_range.start, replace_range.start,
22346                "insert_range and replace_range should start at the same position"
22347            );
22348            debug_assert!(
22349                insert_range
22350                    .start
22351                    .cmp(cursor_position, &buffer_snapshot)
22352                    .is_le(),
22353                "insert_range should start before or at cursor position"
22354            );
22355            debug_assert!(
22356                replace_range
22357                    .start
22358                    .cmp(cursor_position, &buffer_snapshot)
22359                    .is_le(),
22360                "replace_range should start before or at cursor position"
22361            );
22362
22363            let should_replace = match intent {
22364                CompletionIntent::CompleteWithInsert => false,
22365                CompletionIntent::CompleteWithReplace => true,
22366                CompletionIntent::Complete | CompletionIntent::Compose => {
22367                    let insert_mode =
22368                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
22369                            .completions
22370                            .lsp_insert_mode;
22371                    match insert_mode {
22372                        LspInsertMode::Insert => false,
22373                        LspInsertMode::Replace => true,
22374                        LspInsertMode::ReplaceSubsequence => {
22375                            let mut text_to_replace = buffer.chars_for_range(
22376                                buffer.anchor_before(replace_range.start)
22377                                    ..buffer.anchor_after(replace_range.end),
22378                            );
22379                            let mut current_needle = text_to_replace.next();
22380                            for haystack_ch in completion.label.text.chars() {
22381                                if let Some(needle_ch) = current_needle
22382                                    && haystack_ch.eq_ignore_ascii_case(&needle_ch)
22383                                {
22384                                    current_needle = text_to_replace.next();
22385                                }
22386                            }
22387                            current_needle.is_none()
22388                        }
22389                        LspInsertMode::ReplaceSuffix => {
22390                            if replace_range
22391                                .end
22392                                .cmp(cursor_position, &buffer_snapshot)
22393                                .is_gt()
22394                            {
22395                                let range_after_cursor = *cursor_position..replace_range.end;
22396                                let text_after_cursor = buffer
22397                                    .text_for_range(
22398                                        buffer.anchor_before(range_after_cursor.start)
22399                                            ..buffer.anchor_after(range_after_cursor.end),
22400                                    )
22401                                    .collect::<String>()
22402                                    .to_ascii_lowercase();
22403                                completion
22404                                    .label
22405                                    .text
22406                                    .to_ascii_lowercase()
22407                                    .ends_with(&text_after_cursor)
22408                            } else {
22409                                true
22410                            }
22411                        }
22412                    }
22413                }
22414            };
22415
22416            if should_replace {
22417                replace_range.clone()
22418            } else {
22419                insert_range.clone()
22420            }
22421        } else {
22422            replace_range.clone()
22423        }
22424    };
22425
22426    if range_to_replace
22427        .end
22428        .cmp(cursor_position, &buffer_snapshot)
22429        .is_lt()
22430    {
22431        range_to_replace.end = *cursor_position;
22432    }
22433
22434    CompletionEdit {
22435        new_text,
22436        replace_range: range_to_replace.to_offset(buffer),
22437        snippet,
22438    }
22439}
22440
22441struct CompletionEdit {
22442    new_text: String,
22443    replace_range: Range<usize>,
22444    snippet: Option<Snippet>,
22445}
22446
22447fn insert_extra_newline_brackets(
22448    buffer: &MultiBufferSnapshot,
22449    range: Range<usize>,
22450    language: &language::LanguageScope,
22451) -> bool {
22452    let leading_whitespace_len = buffer
22453        .reversed_chars_at(range.start)
22454        .take_while(|c| c.is_whitespace() && *c != '\n')
22455        .map(|c| c.len_utf8())
22456        .sum::<usize>();
22457    let trailing_whitespace_len = buffer
22458        .chars_at(range.end)
22459        .take_while(|c| c.is_whitespace() && *c != '\n')
22460        .map(|c| c.len_utf8())
22461        .sum::<usize>();
22462    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
22463
22464    language.brackets().any(|(pair, enabled)| {
22465        let pair_start = pair.start.trim_end();
22466        let pair_end = pair.end.trim_start();
22467
22468        enabled
22469            && pair.newline
22470            && buffer.contains_str_at(range.end, pair_end)
22471            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
22472    })
22473}
22474
22475fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
22476    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
22477        [(buffer, range, _)] => (*buffer, range.clone()),
22478        _ => return false,
22479    };
22480    let pair = {
22481        let mut result: Option<BracketMatch> = None;
22482
22483        for pair in buffer
22484            .all_bracket_ranges(range.clone())
22485            .filter(move |pair| {
22486                pair.open_range.start <= range.start && pair.close_range.end >= range.end
22487            })
22488        {
22489            let len = pair.close_range.end - pair.open_range.start;
22490
22491            if let Some(existing) = &result {
22492                let existing_len = existing.close_range.end - existing.open_range.start;
22493                if len > existing_len {
22494                    continue;
22495                }
22496            }
22497
22498            result = Some(pair);
22499        }
22500
22501        result
22502    };
22503    let Some(pair) = pair else {
22504        return false;
22505    };
22506    pair.newline_only
22507        && buffer
22508            .chars_for_range(pair.open_range.end..range.start)
22509            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
22510            .all(|c| c.is_whitespace() && c != '\n')
22511}
22512
22513fn update_uncommitted_diff_for_buffer(
22514    editor: Entity<Editor>,
22515    project: &Entity<Project>,
22516    buffers: impl IntoIterator<Item = Entity<Buffer>>,
22517    buffer: Entity<MultiBuffer>,
22518    cx: &mut App,
22519) -> Task<()> {
22520    let mut tasks = Vec::new();
22521    project.update(cx, |project, cx| {
22522        for buffer in buffers {
22523            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
22524                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
22525            }
22526        }
22527    });
22528    cx.spawn(async move |cx| {
22529        let diffs = future::join_all(tasks).await;
22530        if editor
22531            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
22532            .unwrap_or(false)
22533        {
22534            return;
22535        }
22536
22537        buffer
22538            .update(cx, |buffer, cx| {
22539                for diff in diffs.into_iter().flatten() {
22540                    buffer.add_diff(diff, cx);
22541                }
22542            })
22543            .ok();
22544    })
22545}
22546
22547fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
22548    let tab_size = tab_size.get() as usize;
22549    let mut width = offset;
22550
22551    for ch in text.chars() {
22552        width += if ch == '\t' {
22553            tab_size - (width % tab_size)
22554        } else {
22555            1
22556        };
22557    }
22558
22559    width - offset
22560}
22561
22562#[cfg(test)]
22563mod tests {
22564    use super::*;
22565
22566    #[test]
22567    fn test_string_size_with_expanded_tabs() {
22568        let nz = |val| NonZeroU32::new(val).unwrap();
22569        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
22570        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
22571        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
22572        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
22573        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
22574        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
22575        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
22576        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
22577    }
22578}
22579
22580/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
22581struct WordBreakingTokenizer<'a> {
22582    input: &'a str,
22583}
22584
22585impl<'a> WordBreakingTokenizer<'a> {
22586    fn new(input: &'a str) -> Self {
22587        Self { input }
22588    }
22589}
22590
22591fn is_char_ideographic(ch: char) -> bool {
22592    use unicode_script::Script::*;
22593    use unicode_script::UnicodeScript;
22594    matches!(ch.script(), Han | Tangut | Yi)
22595}
22596
22597fn is_grapheme_ideographic(text: &str) -> bool {
22598    text.chars().any(is_char_ideographic)
22599}
22600
22601fn is_grapheme_whitespace(text: &str) -> bool {
22602    text.chars().any(|x| x.is_whitespace())
22603}
22604
22605fn should_stay_with_preceding_ideograph(text: &str) -> bool {
22606    text.chars()
22607        .next()
22608        .is_some_and(|ch| matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…'))
22609}
22610
22611#[derive(PartialEq, Eq, Debug, Clone, Copy)]
22612enum WordBreakToken<'a> {
22613    Word { token: &'a str, grapheme_len: usize },
22614    InlineWhitespace { token: &'a str, grapheme_len: usize },
22615    Newline,
22616}
22617
22618impl<'a> Iterator for WordBreakingTokenizer<'a> {
22619    /// Yields a span, the count of graphemes in the token, and whether it was
22620    /// whitespace. Note that it also breaks at word boundaries.
22621    type Item = WordBreakToken<'a>;
22622
22623    fn next(&mut self) -> Option<Self::Item> {
22624        use unicode_segmentation::UnicodeSegmentation;
22625        if self.input.is_empty() {
22626            return None;
22627        }
22628
22629        let mut iter = self.input.graphemes(true).peekable();
22630        let mut offset = 0;
22631        let mut grapheme_len = 0;
22632        if let Some(first_grapheme) = iter.next() {
22633            let is_newline = first_grapheme == "\n";
22634            let is_whitespace = is_grapheme_whitespace(first_grapheme);
22635            offset += first_grapheme.len();
22636            grapheme_len += 1;
22637            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
22638                if let Some(grapheme) = iter.peek().copied()
22639                    && should_stay_with_preceding_ideograph(grapheme)
22640                {
22641                    offset += grapheme.len();
22642                    grapheme_len += 1;
22643                }
22644            } else {
22645                let mut words = self.input[offset..].split_word_bound_indices().peekable();
22646                let mut next_word_bound = words.peek().copied();
22647                if next_word_bound.is_some_and(|(i, _)| i == 0) {
22648                    next_word_bound = words.next();
22649                }
22650                while let Some(grapheme) = iter.peek().copied() {
22651                    if next_word_bound.is_some_and(|(i, _)| i == offset) {
22652                        break;
22653                    };
22654                    if is_grapheme_whitespace(grapheme) != is_whitespace
22655                        || (grapheme == "\n") != is_newline
22656                    {
22657                        break;
22658                    };
22659                    offset += grapheme.len();
22660                    grapheme_len += 1;
22661                    iter.next();
22662                }
22663            }
22664            let token = &self.input[..offset];
22665            self.input = &self.input[offset..];
22666            if token == "\n" {
22667                Some(WordBreakToken::Newline)
22668            } else if is_whitespace {
22669                Some(WordBreakToken::InlineWhitespace {
22670                    token,
22671                    grapheme_len,
22672                })
22673            } else {
22674                Some(WordBreakToken::Word {
22675                    token,
22676                    grapheme_len,
22677                })
22678            }
22679        } else {
22680            None
22681        }
22682    }
22683}
22684
22685#[test]
22686fn test_word_breaking_tokenizer() {
22687    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
22688        ("", &[]),
22689        ("  ", &[whitespace("  ", 2)]),
22690        ("Ʒ", &[word("Ʒ", 1)]),
22691        ("Ǽ", &[word("Ǽ", 1)]),
22692        ("", &[word("", 1)]),
22693        ("⋑⋑", &[word("⋑⋑", 2)]),
22694        (
22695            "原理,进而",
22696            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
22697        ),
22698        (
22699            "hello world",
22700            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
22701        ),
22702        (
22703            "hello, world",
22704            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
22705        ),
22706        (
22707            "  hello world",
22708            &[
22709                whitespace("  ", 2),
22710                word("hello", 5),
22711                whitespace(" ", 1),
22712                word("world", 5),
22713            ],
22714        ),
22715        (
22716            "这是什么 \n 钢笔",
22717            &[
22718                word("", 1),
22719                word("", 1),
22720                word("", 1),
22721                word("", 1),
22722                whitespace(" ", 1),
22723                newline(),
22724                whitespace(" ", 1),
22725                word("", 1),
22726                word("", 1),
22727            ],
22728        ),
22729        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
22730    ];
22731
22732    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
22733        WordBreakToken::Word {
22734            token,
22735            grapheme_len,
22736        }
22737    }
22738
22739    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
22740        WordBreakToken::InlineWhitespace {
22741            token,
22742            grapheme_len,
22743        }
22744    }
22745
22746    fn newline() -> WordBreakToken<'static> {
22747        WordBreakToken::Newline
22748    }
22749
22750    for (input, result) in tests {
22751        assert_eq!(
22752            WordBreakingTokenizer::new(input)
22753                .collect::<Vec<_>>()
22754                .as_slice(),
22755            *result,
22756        );
22757    }
22758}
22759
22760fn wrap_with_prefix(
22761    first_line_prefix: String,
22762    subsequent_lines_prefix: String,
22763    unwrapped_text: String,
22764    wrap_column: usize,
22765    tab_size: NonZeroU32,
22766    preserve_existing_whitespace: bool,
22767) -> String {
22768    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
22769    let subsequent_lines_prefix_len =
22770        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
22771    let mut wrapped_text = String::new();
22772    let mut current_line = first_line_prefix;
22773    let mut is_first_line = true;
22774
22775    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
22776    let mut current_line_len = first_line_prefix_len;
22777    let mut in_whitespace = false;
22778    for token in tokenizer {
22779        let have_preceding_whitespace = in_whitespace;
22780        match token {
22781            WordBreakToken::Word {
22782                token,
22783                grapheme_len,
22784            } => {
22785                in_whitespace = false;
22786                let current_prefix_len = if is_first_line {
22787                    first_line_prefix_len
22788                } else {
22789                    subsequent_lines_prefix_len
22790                };
22791                if current_line_len + grapheme_len > wrap_column
22792                    && current_line_len != current_prefix_len
22793                {
22794                    wrapped_text.push_str(current_line.trim_end());
22795                    wrapped_text.push('\n');
22796                    is_first_line = false;
22797                    current_line = subsequent_lines_prefix.clone();
22798                    current_line_len = subsequent_lines_prefix_len;
22799                }
22800                current_line.push_str(token);
22801                current_line_len += grapheme_len;
22802            }
22803            WordBreakToken::InlineWhitespace {
22804                mut token,
22805                mut grapheme_len,
22806            } => {
22807                in_whitespace = true;
22808                if have_preceding_whitespace && !preserve_existing_whitespace {
22809                    continue;
22810                }
22811                if !preserve_existing_whitespace {
22812                    // Keep a single whitespace grapheme as-is
22813                    if let Some(first) =
22814                        unicode_segmentation::UnicodeSegmentation::graphemes(token, true).next()
22815                    {
22816                        token = first;
22817                    } else {
22818                        token = " ";
22819                    }
22820                    grapheme_len = 1;
22821                }
22822                let current_prefix_len = if is_first_line {
22823                    first_line_prefix_len
22824                } else {
22825                    subsequent_lines_prefix_len
22826                };
22827                if current_line_len + grapheme_len > wrap_column {
22828                    wrapped_text.push_str(current_line.trim_end());
22829                    wrapped_text.push('\n');
22830                    is_first_line = false;
22831                    current_line = subsequent_lines_prefix.clone();
22832                    current_line_len = subsequent_lines_prefix_len;
22833                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
22834                    current_line.push_str(token);
22835                    current_line_len += grapheme_len;
22836                }
22837            }
22838            WordBreakToken::Newline => {
22839                in_whitespace = true;
22840                let current_prefix_len = if is_first_line {
22841                    first_line_prefix_len
22842                } else {
22843                    subsequent_lines_prefix_len
22844                };
22845                if preserve_existing_whitespace {
22846                    wrapped_text.push_str(current_line.trim_end());
22847                    wrapped_text.push('\n');
22848                    is_first_line = false;
22849                    current_line = subsequent_lines_prefix.clone();
22850                    current_line_len = subsequent_lines_prefix_len;
22851                } else if have_preceding_whitespace {
22852                    continue;
22853                } else if current_line_len + 1 > wrap_column
22854                    && current_line_len != current_prefix_len
22855                {
22856                    wrapped_text.push_str(current_line.trim_end());
22857                    wrapped_text.push('\n');
22858                    is_first_line = false;
22859                    current_line = subsequent_lines_prefix.clone();
22860                    current_line_len = subsequent_lines_prefix_len;
22861                } else if current_line_len != current_prefix_len {
22862                    current_line.push(' ');
22863                    current_line_len += 1;
22864                }
22865            }
22866        }
22867    }
22868
22869    if !current_line.is_empty() {
22870        wrapped_text.push_str(&current_line);
22871    }
22872    wrapped_text
22873}
22874
22875#[test]
22876fn test_wrap_with_prefix() {
22877    assert_eq!(
22878        wrap_with_prefix(
22879            "# ".to_string(),
22880            "# ".to_string(),
22881            "abcdefg".to_string(),
22882            4,
22883            NonZeroU32::new(4).unwrap(),
22884            false,
22885        ),
22886        "# abcdefg"
22887    );
22888    assert_eq!(
22889        wrap_with_prefix(
22890            "".to_string(),
22891            "".to_string(),
22892            "\thello world".to_string(),
22893            8,
22894            NonZeroU32::new(4).unwrap(),
22895            false,
22896        ),
22897        "hello\nworld"
22898    );
22899    assert_eq!(
22900        wrap_with_prefix(
22901            "// ".to_string(),
22902            "// ".to_string(),
22903            "xx \nyy zz aa bb cc".to_string(),
22904            12,
22905            NonZeroU32::new(4).unwrap(),
22906            false,
22907        ),
22908        "// xx yy zz\n// aa bb cc"
22909    );
22910    assert_eq!(
22911        wrap_with_prefix(
22912            String::new(),
22913            String::new(),
22914            "这是什么 \n 钢笔".to_string(),
22915            3,
22916            NonZeroU32::new(4).unwrap(),
22917            false,
22918        ),
22919        "这是什\n么 钢\n"
22920    );
22921    assert_eq!(
22922        wrap_with_prefix(
22923            String::new(),
22924            String::new(),
22925            format!("foo{}bar", '\u{2009}'), // thin space
22926            80,
22927            NonZeroU32::new(4).unwrap(),
22928            false,
22929        ),
22930        format!("foo{}bar", '\u{2009}')
22931    );
22932}
22933
22934pub trait CollaborationHub {
22935    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
22936    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
22937    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
22938}
22939
22940impl CollaborationHub for Entity<Project> {
22941    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
22942        self.read(cx).collaborators()
22943    }
22944
22945    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
22946        self.read(cx).user_store().read(cx).participant_indices()
22947    }
22948
22949    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
22950        let this = self.read(cx);
22951        let user_ids = this.collaborators().values().map(|c| c.user_id);
22952        this.user_store().read(cx).participant_names(user_ids, cx)
22953    }
22954}
22955
22956pub trait SemanticsProvider {
22957    fn hover(
22958        &self,
22959        buffer: &Entity<Buffer>,
22960        position: text::Anchor,
22961        cx: &mut App,
22962    ) -> Option<Task<Option<Vec<project::Hover>>>>;
22963
22964    fn inline_values(
22965        &self,
22966        buffer_handle: Entity<Buffer>,
22967        range: Range<text::Anchor>,
22968        cx: &mut App,
22969    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
22970
22971    fn applicable_inlay_chunks(
22972        &self,
22973        buffer: &Entity<Buffer>,
22974        ranges: &[Range<text::Anchor>],
22975        cx: &mut App,
22976    ) -> Vec<Range<BufferRow>>;
22977
22978    fn invalidate_inlay_hints(&self, for_buffers: &HashSet<BufferId>, cx: &mut App);
22979
22980    fn inlay_hints(
22981        &self,
22982        invalidate: InvalidationStrategy,
22983        buffer: Entity<Buffer>,
22984        ranges: Vec<Range<text::Anchor>>,
22985        known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
22986        cx: &mut App,
22987    ) -> Option<HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>>>;
22988
22989    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
22990
22991    fn document_highlights(
22992        &self,
22993        buffer: &Entity<Buffer>,
22994        position: text::Anchor,
22995        cx: &mut App,
22996    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
22997
22998    fn definitions(
22999        &self,
23000        buffer: &Entity<Buffer>,
23001        position: text::Anchor,
23002        kind: GotoDefinitionKind,
23003        cx: &mut App,
23004    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>>;
23005
23006    fn range_for_rename(
23007        &self,
23008        buffer: &Entity<Buffer>,
23009        position: text::Anchor,
23010        cx: &mut App,
23011    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
23012
23013    fn perform_rename(
23014        &self,
23015        buffer: &Entity<Buffer>,
23016        position: text::Anchor,
23017        new_name: String,
23018        cx: &mut App,
23019    ) -> Option<Task<Result<ProjectTransaction>>>;
23020}
23021
23022pub trait CompletionProvider {
23023    fn completions(
23024        &self,
23025        excerpt_id: ExcerptId,
23026        buffer: &Entity<Buffer>,
23027        buffer_position: text::Anchor,
23028        trigger: CompletionContext,
23029        window: &mut Window,
23030        cx: &mut Context<Editor>,
23031    ) -> Task<Result<Vec<CompletionResponse>>>;
23032
23033    fn resolve_completions(
23034        &self,
23035        _buffer: Entity<Buffer>,
23036        _completion_indices: Vec<usize>,
23037        _completions: Rc<RefCell<Box<[Completion]>>>,
23038        _cx: &mut Context<Editor>,
23039    ) -> Task<Result<bool>> {
23040        Task::ready(Ok(false))
23041    }
23042
23043    fn apply_additional_edits_for_completion(
23044        &self,
23045        _buffer: Entity<Buffer>,
23046        _completions: Rc<RefCell<Box<[Completion]>>>,
23047        _completion_index: usize,
23048        _push_to_history: bool,
23049        _cx: &mut Context<Editor>,
23050    ) -> Task<Result<Option<language::Transaction>>> {
23051        Task::ready(Ok(None))
23052    }
23053
23054    fn is_completion_trigger(
23055        &self,
23056        buffer: &Entity<Buffer>,
23057        position: language::Anchor,
23058        text: &str,
23059        trigger_in_words: bool,
23060        menu_is_open: bool,
23061        cx: &mut Context<Editor>,
23062    ) -> bool;
23063
23064    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
23065
23066    fn sort_completions(&self) -> bool {
23067        true
23068    }
23069
23070    fn filter_completions(&self) -> bool {
23071        true
23072    }
23073
23074    fn show_snippets(&self) -> bool {
23075        false
23076    }
23077}
23078
23079pub trait CodeActionProvider {
23080    fn id(&self) -> Arc<str>;
23081
23082    fn code_actions(
23083        &self,
23084        buffer: &Entity<Buffer>,
23085        range: Range<text::Anchor>,
23086        window: &mut Window,
23087        cx: &mut App,
23088    ) -> Task<Result<Vec<CodeAction>>>;
23089
23090    fn apply_code_action(
23091        &self,
23092        buffer_handle: Entity<Buffer>,
23093        action: CodeAction,
23094        excerpt_id: ExcerptId,
23095        push_to_history: bool,
23096        window: &mut Window,
23097        cx: &mut App,
23098    ) -> Task<Result<ProjectTransaction>>;
23099}
23100
23101impl CodeActionProvider for Entity<Project> {
23102    fn id(&self) -> Arc<str> {
23103        "project".into()
23104    }
23105
23106    fn code_actions(
23107        &self,
23108        buffer: &Entity<Buffer>,
23109        range: Range<text::Anchor>,
23110        _window: &mut Window,
23111        cx: &mut App,
23112    ) -> Task<Result<Vec<CodeAction>>> {
23113        self.update(cx, |project, cx| {
23114            let code_lens_actions = project.code_lens_actions(buffer, range.clone(), cx);
23115            let code_actions = project.code_actions(buffer, range, None, cx);
23116            cx.background_spawn(async move {
23117                let (code_lens_actions, code_actions) = join(code_lens_actions, code_actions).await;
23118                Ok(code_lens_actions
23119                    .context("code lens fetch")?
23120                    .into_iter()
23121                    .flatten()
23122                    .chain(
23123                        code_actions
23124                            .context("code action fetch")?
23125                            .into_iter()
23126                            .flatten(),
23127                    )
23128                    .collect())
23129            })
23130        })
23131    }
23132
23133    fn apply_code_action(
23134        &self,
23135        buffer_handle: Entity<Buffer>,
23136        action: CodeAction,
23137        _excerpt_id: ExcerptId,
23138        push_to_history: bool,
23139        _window: &mut Window,
23140        cx: &mut App,
23141    ) -> Task<Result<ProjectTransaction>> {
23142        self.update(cx, |project, cx| {
23143            project.apply_code_action(buffer_handle, action, push_to_history, cx)
23144        })
23145    }
23146}
23147
23148fn snippet_completions(
23149    project: &Project,
23150    buffer: &Entity<Buffer>,
23151    buffer_position: text::Anchor,
23152    cx: &mut App,
23153) -> Task<Result<CompletionResponse>> {
23154    let languages = buffer.read(cx).languages_at(buffer_position);
23155    let snippet_store = project.snippets().read(cx);
23156
23157    let scopes: Vec<_> = languages
23158        .iter()
23159        .filter_map(|language| {
23160            let language_name = language.lsp_id();
23161            let snippets = snippet_store.snippets_for(Some(language_name), cx);
23162
23163            if snippets.is_empty() {
23164                None
23165            } else {
23166                Some((language.default_scope(), snippets))
23167            }
23168        })
23169        .collect();
23170
23171    if scopes.is_empty() {
23172        return Task::ready(Ok(CompletionResponse {
23173            completions: vec![],
23174            display_options: CompletionDisplayOptions::default(),
23175            is_incomplete: false,
23176        }));
23177    }
23178
23179    let snapshot = buffer.read(cx).text_snapshot();
23180    let executor = cx.background_executor().clone();
23181
23182    cx.background_spawn(async move {
23183        let mut is_incomplete = false;
23184        let mut completions: Vec<Completion> = Vec::new();
23185        for (scope, snippets) in scopes.into_iter() {
23186            let classifier =
23187                CharClassifier::new(Some(scope)).scope_context(Some(CharScopeContext::Completion));
23188
23189            const MAX_WORD_PREFIX_LEN: usize = 128;
23190            let last_word: String = snapshot
23191                .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
23192                .take(MAX_WORD_PREFIX_LEN)
23193                .take_while(|c| classifier.is_word(*c))
23194                .collect::<String>()
23195                .chars()
23196                .rev()
23197                .collect();
23198
23199            if last_word.is_empty() {
23200                return Ok(CompletionResponse {
23201                    completions: vec![],
23202                    display_options: CompletionDisplayOptions::default(),
23203                    is_incomplete: true,
23204                });
23205            }
23206
23207            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
23208            let to_lsp = |point: &text::Anchor| {
23209                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
23210                point_to_lsp(end)
23211            };
23212            let lsp_end = to_lsp(&buffer_position);
23213
23214            let candidates = snippets
23215                .iter()
23216                .enumerate()
23217                .flat_map(|(ix, snippet)| {
23218                    snippet
23219                        .prefix
23220                        .iter()
23221                        .map(move |prefix| StringMatchCandidate::new(ix, prefix))
23222                })
23223                .collect::<Vec<StringMatchCandidate>>();
23224
23225            const MAX_RESULTS: usize = 100;
23226            let mut matches = fuzzy::match_strings(
23227                &candidates,
23228                &last_word,
23229                last_word.chars().any(|c| c.is_uppercase()),
23230                true,
23231                MAX_RESULTS,
23232                &Default::default(),
23233                executor.clone(),
23234            )
23235            .await;
23236
23237            if matches.len() >= MAX_RESULTS {
23238                is_incomplete = true;
23239            }
23240
23241            // Remove all candidates where the query's start does not match the start of any word in the candidate
23242            if let Some(query_start) = last_word.chars().next() {
23243                matches.retain(|string_match| {
23244                    split_words(&string_match.string).any(|word| {
23245                        // Check that the first codepoint of the word as lowercase matches the first
23246                        // codepoint of the query as lowercase
23247                        word.chars()
23248                            .flat_map(|codepoint| codepoint.to_lowercase())
23249                            .zip(query_start.to_lowercase())
23250                            .all(|(word_cp, query_cp)| word_cp == query_cp)
23251                    })
23252                });
23253            }
23254
23255            let matched_strings = matches
23256                .into_iter()
23257                .map(|m| m.string)
23258                .collect::<HashSet<_>>();
23259
23260            completions.extend(snippets.iter().filter_map(|snippet| {
23261                let matching_prefix = snippet
23262                    .prefix
23263                    .iter()
23264                    .find(|prefix| matched_strings.contains(*prefix))?;
23265                let start = as_offset - last_word.len();
23266                let start = snapshot.anchor_before(start);
23267                let range = start..buffer_position;
23268                let lsp_start = to_lsp(&start);
23269                let lsp_range = lsp::Range {
23270                    start: lsp_start,
23271                    end: lsp_end,
23272                };
23273                Some(Completion {
23274                    replace_range: range,
23275                    new_text: snippet.body.clone(),
23276                    source: CompletionSource::Lsp {
23277                        insert_range: None,
23278                        server_id: LanguageServerId(usize::MAX),
23279                        resolved: true,
23280                        lsp_completion: Box::new(lsp::CompletionItem {
23281                            label: snippet.prefix.first().unwrap().clone(),
23282                            kind: Some(CompletionItemKind::SNIPPET),
23283                            label_details: snippet.description.as_ref().map(|description| {
23284                                lsp::CompletionItemLabelDetails {
23285                                    detail: Some(description.clone()),
23286                                    description: None,
23287                                }
23288                            }),
23289                            insert_text_format: Some(InsertTextFormat::SNIPPET),
23290                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
23291                                lsp::InsertReplaceEdit {
23292                                    new_text: snippet.body.clone(),
23293                                    insert: lsp_range,
23294                                    replace: lsp_range,
23295                                },
23296                            )),
23297                            filter_text: Some(snippet.body.clone()),
23298                            sort_text: Some(char::MAX.to_string()),
23299                            ..lsp::CompletionItem::default()
23300                        }),
23301                        lsp_defaults: None,
23302                    },
23303                    label: CodeLabel::plain(matching_prefix.clone(), None),
23304                    icon_path: None,
23305                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
23306                        single_line: snippet.name.clone().into(),
23307                        plain_text: snippet
23308                            .description
23309                            .clone()
23310                            .map(|description| description.into()),
23311                    }),
23312                    insert_text_mode: None,
23313                    confirm: None,
23314                })
23315            }))
23316        }
23317
23318        Ok(CompletionResponse {
23319            completions,
23320            display_options: CompletionDisplayOptions::default(),
23321            is_incomplete,
23322        })
23323    })
23324}
23325
23326impl CompletionProvider for Entity<Project> {
23327    fn completions(
23328        &self,
23329        _excerpt_id: ExcerptId,
23330        buffer: &Entity<Buffer>,
23331        buffer_position: text::Anchor,
23332        options: CompletionContext,
23333        _window: &mut Window,
23334        cx: &mut Context<Editor>,
23335    ) -> Task<Result<Vec<CompletionResponse>>> {
23336        self.update(cx, |project, cx| {
23337            let task = project.completions(buffer, buffer_position, options, cx);
23338            cx.background_spawn(task)
23339        })
23340    }
23341
23342    fn resolve_completions(
23343        &self,
23344        buffer: Entity<Buffer>,
23345        completion_indices: Vec<usize>,
23346        completions: Rc<RefCell<Box<[Completion]>>>,
23347        cx: &mut Context<Editor>,
23348    ) -> Task<Result<bool>> {
23349        self.update(cx, |project, cx| {
23350            project.lsp_store().update(cx, |lsp_store, cx| {
23351                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
23352            })
23353        })
23354    }
23355
23356    fn apply_additional_edits_for_completion(
23357        &self,
23358        buffer: Entity<Buffer>,
23359        completions: Rc<RefCell<Box<[Completion]>>>,
23360        completion_index: usize,
23361        push_to_history: bool,
23362        cx: &mut Context<Editor>,
23363    ) -> Task<Result<Option<language::Transaction>>> {
23364        self.update(cx, |project, cx| {
23365            project.lsp_store().update(cx, |lsp_store, cx| {
23366                lsp_store.apply_additional_edits_for_completion(
23367                    buffer,
23368                    completions,
23369                    completion_index,
23370                    push_to_history,
23371                    cx,
23372                )
23373            })
23374        })
23375    }
23376
23377    fn is_completion_trigger(
23378        &self,
23379        buffer: &Entity<Buffer>,
23380        position: language::Anchor,
23381        text: &str,
23382        trigger_in_words: bool,
23383        menu_is_open: bool,
23384        cx: &mut Context<Editor>,
23385    ) -> bool {
23386        let mut chars = text.chars();
23387        let char = if let Some(char) = chars.next() {
23388            char
23389        } else {
23390            return false;
23391        };
23392        if chars.next().is_some() {
23393            return false;
23394        }
23395
23396        let buffer = buffer.read(cx);
23397        let snapshot = buffer.snapshot();
23398        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
23399            return false;
23400        }
23401        let classifier = snapshot
23402            .char_classifier_at(position)
23403            .scope_context(Some(CharScopeContext::Completion));
23404        if trigger_in_words && classifier.is_word(char) {
23405            return true;
23406        }
23407
23408        buffer.completion_triggers().contains(text)
23409    }
23410
23411    fn show_snippets(&self) -> bool {
23412        true
23413    }
23414}
23415
23416impl SemanticsProvider for Entity<Project> {
23417    fn hover(
23418        &self,
23419        buffer: &Entity<Buffer>,
23420        position: text::Anchor,
23421        cx: &mut App,
23422    ) -> Option<Task<Option<Vec<project::Hover>>>> {
23423        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
23424    }
23425
23426    fn document_highlights(
23427        &self,
23428        buffer: &Entity<Buffer>,
23429        position: text::Anchor,
23430        cx: &mut App,
23431    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
23432        Some(self.update(cx, |project, cx| {
23433            project.document_highlights(buffer, position, cx)
23434        }))
23435    }
23436
23437    fn definitions(
23438        &self,
23439        buffer: &Entity<Buffer>,
23440        position: text::Anchor,
23441        kind: GotoDefinitionKind,
23442        cx: &mut App,
23443    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>> {
23444        Some(self.update(cx, |project, cx| match kind {
23445            GotoDefinitionKind::Symbol => project.definitions(buffer, position, cx),
23446            GotoDefinitionKind::Declaration => project.declarations(buffer, position, cx),
23447            GotoDefinitionKind::Type => project.type_definitions(buffer, position, cx),
23448            GotoDefinitionKind::Implementation => project.implementations(buffer, position, cx),
23449        }))
23450    }
23451
23452    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
23453        self.update(cx, |project, cx| {
23454            if project
23455                .active_debug_session(cx)
23456                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
23457            {
23458                return true;
23459            }
23460
23461            buffer.update(cx, |buffer, cx| {
23462                project.any_language_server_supports_inlay_hints(buffer, cx)
23463            })
23464        })
23465    }
23466
23467    fn inline_values(
23468        &self,
23469        buffer_handle: Entity<Buffer>,
23470        range: Range<text::Anchor>,
23471        cx: &mut App,
23472    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
23473        self.update(cx, |project, cx| {
23474            let (session, active_stack_frame) = project.active_debug_session(cx)?;
23475
23476            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
23477        })
23478    }
23479
23480    fn applicable_inlay_chunks(
23481        &self,
23482        buffer: &Entity<Buffer>,
23483        ranges: &[Range<text::Anchor>],
23484        cx: &mut App,
23485    ) -> Vec<Range<BufferRow>> {
23486        self.read(cx).lsp_store().update(cx, |lsp_store, cx| {
23487            lsp_store.applicable_inlay_chunks(buffer, ranges, cx)
23488        })
23489    }
23490
23491    fn invalidate_inlay_hints(&self, for_buffers: &HashSet<BufferId>, cx: &mut App) {
23492        self.read(cx).lsp_store().update(cx, |lsp_store, _| {
23493            lsp_store.invalidate_inlay_hints(for_buffers)
23494        });
23495    }
23496
23497    fn inlay_hints(
23498        &self,
23499        invalidate: InvalidationStrategy,
23500        buffer: Entity<Buffer>,
23501        ranges: Vec<Range<text::Anchor>>,
23502        known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
23503        cx: &mut App,
23504    ) -> Option<HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>>> {
23505        Some(self.read(cx).lsp_store().update(cx, |lsp_store, cx| {
23506            lsp_store.inlay_hints(invalidate, buffer, ranges, known_chunks, cx)
23507        }))
23508    }
23509
23510    fn range_for_rename(
23511        &self,
23512        buffer: &Entity<Buffer>,
23513        position: text::Anchor,
23514        cx: &mut App,
23515    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
23516        Some(self.update(cx, |project, cx| {
23517            let buffer = buffer.clone();
23518            let task = project.prepare_rename(buffer.clone(), position, cx);
23519            cx.spawn(async move |_, cx| {
23520                Ok(match task.await? {
23521                    PrepareRenameResponse::Success(range) => Some(range),
23522                    PrepareRenameResponse::InvalidPosition => None,
23523                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
23524                        // Fallback on using TreeSitter info to determine identifier range
23525                        buffer.read_with(cx, |buffer, _| {
23526                            let snapshot = buffer.snapshot();
23527                            let (range, kind) = snapshot.surrounding_word(position, None);
23528                            if kind != Some(CharKind::Word) {
23529                                return None;
23530                            }
23531                            Some(
23532                                snapshot.anchor_before(range.start)
23533                                    ..snapshot.anchor_after(range.end),
23534                            )
23535                        })?
23536                    }
23537                })
23538            })
23539        }))
23540    }
23541
23542    fn perform_rename(
23543        &self,
23544        buffer: &Entity<Buffer>,
23545        position: text::Anchor,
23546        new_name: String,
23547        cx: &mut App,
23548    ) -> Option<Task<Result<ProjectTransaction>>> {
23549        Some(self.update(cx, |project, cx| {
23550            project.perform_rename(buffer.clone(), position, new_name, cx)
23551        }))
23552    }
23553}
23554
23555fn consume_contiguous_rows(
23556    contiguous_row_selections: &mut Vec<Selection<Point>>,
23557    selection: &Selection<Point>,
23558    display_map: &DisplaySnapshot,
23559    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
23560) -> (MultiBufferRow, MultiBufferRow) {
23561    contiguous_row_selections.push(selection.clone());
23562    let start_row = starting_row(selection, display_map);
23563    let mut end_row = ending_row(selection, display_map);
23564
23565    while let Some(next_selection) = selections.peek() {
23566        if next_selection.start.row <= end_row.0 {
23567            end_row = ending_row(next_selection, display_map);
23568            contiguous_row_selections.push(selections.next().unwrap().clone());
23569        } else {
23570            break;
23571        }
23572    }
23573    (start_row, end_row)
23574}
23575
23576fn starting_row(selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
23577    if selection.start.column > 0 {
23578        MultiBufferRow(display_map.prev_line_boundary(selection.start).0.row)
23579    } else {
23580        MultiBufferRow(selection.start.row)
23581    }
23582}
23583
23584fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
23585    if next_selection.end.column > 0 || next_selection.is_empty() {
23586        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
23587    } else {
23588        MultiBufferRow(next_selection.end.row)
23589    }
23590}
23591
23592impl EditorSnapshot {
23593    pub fn remote_selections_in_range<'a>(
23594        &'a self,
23595        range: &'a Range<Anchor>,
23596        collaboration_hub: &dyn CollaborationHub,
23597        cx: &'a App,
23598    ) -> impl 'a + Iterator<Item = RemoteSelection> {
23599        let participant_names = collaboration_hub.user_names(cx);
23600        let participant_indices = collaboration_hub.user_participant_indices(cx);
23601        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
23602        let collaborators_by_replica_id = collaborators_by_peer_id
23603            .values()
23604            .map(|collaborator| (collaborator.replica_id, collaborator))
23605            .collect::<HashMap<_, _>>();
23606        self.buffer_snapshot()
23607            .selections_in_range(range, false)
23608            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
23609                if replica_id == ReplicaId::AGENT {
23610                    Some(RemoteSelection {
23611                        replica_id,
23612                        selection,
23613                        cursor_shape,
23614                        line_mode,
23615                        collaborator_id: CollaboratorId::Agent,
23616                        user_name: Some("Agent".into()),
23617                        color: cx.theme().players().agent(),
23618                    })
23619                } else {
23620                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
23621                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
23622                    let user_name = participant_names.get(&collaborator.user_id).cloned();
23623                    Some(RemoteSelection {
23624                        replica_id,
23625                        selection,
23626                        cursor_shape,
23627                        line_mode,
23628                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
23629                        user_name,
23630                        color: if let Some(index) = participant_index {
23631                            cx.theme().players().color_for_participant(index.0)
23632                        } else {
23633                            cx.theme().players().absent()
23634                        },
23635                    })
23636                }
23637            })
23638    }
23639
23640    pub fn hunks_for_ranges(
23641        &self,
23642        ranges: impl IntoIterator<Item = Range<Point>>,
23643    ) -> Vec<MultiBufferDiffHunk> {
23644        let mut hunks = Vec::new();
23645        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
23646            HashMap::default();
23647        for query_range in ranges {
23648            let query_rows =
23649                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
23650            for hunk in self.buffer_snapshot().diff_hunks_in_range(
23651                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
23652            ) {
23653                // Include deleted hunks that are adjacent to the query range, because
23654                // otherwise they would be missed.
23655                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
23656                if hunk.status().is_deleted() {
23657                    intersects_range |= hunk.row_range.start == query_rows.end;
23658                    intersects_range |= hunk.row_range.end == query_rows.start;
23659                }
23660                if intersects_range {
23661                    if !processed_buffer_rows
23662                        .entry(hunk.buffer_id)
23663                        .or_default()
23664                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
23665                    {
23666                        continue;
23667                    }
23668                    hunks.push(hunk);
23669                }
23670            }
23671        }
23672
23673        hunks
23674    }
23675
23676    fn display_diff_hunks_for_rows<'a>(
23677        &'a self,
23678        display_rows: Range<DisplayRow>,
23679        folded_buffers: &'a HashSet<BufferId>,
23680    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
23681        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
23682        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
23683
23684        self.buffer_snapshot()
23685            .diff_hunks_in_range(buffer_start..buffer_end)
23686            .filter_map(|hunk| {
23687                if folded_buffers.contains(&hunk.buffer_id) {
23688                    return None;
23689                }
23690
23691                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
23692                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
23693
23694                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
23695                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
23696
23697                let display_hunk = if hunk_display_start.column() != 0 {
23698                    DisplayDiffHunk::Folded {
23699                        display_row: hunk_display_start.row(),
23700                    }
23701                } else {
23702                    let mut end_row = hunk_display_end.row();
23703                    if hunk_display_end.column() > 0 {
23704                        end_row.0 += 1;
23705                    }
23706                    let is_created_file = hunk.is_created_file();
23707                    DisplayDiffHunk::Unfolded {
23708                        status: hunk.status(),
23709                        diff_base_byte_range: hunk.diff_base_byte_range,
23710                        display_row_range: hunk_display_start.row()..end_row,
23711                        multi_buffer_range: Anchor::range_in_buffer(
23712                            hunk.excerpt_id,
23713                            hunk.buffer_id,
23714                            hunk.buffer_range,
23715                        ),
23716                        is_created_file,
23717                    }
23718                };
23719
23720                Some(display_hunk)
23721            })
23722    }
23723
23724    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
23725        self.display_snapshot
23726            .buffer_snapshot()
23727            .language_at(position)
23728    }
23729
23730    pub fn is_focused(&self) -> bool {
23731        self.is_focused
23732    }
23733
23734    pub fn placeholder_text(&self) -> Option<String> {
23735        self.placeholder_display_snapshot
23736            .as_ref()
23737            .map(|display_map| display_map.text())
23738    }
23739
23740    pub fn scroll_position(&self) -> gpui::Point<ScrollOffset> {
23741        self.scroll_anchor.scroll_position(&self.display_snapshot)
23742    }
23743
23744    fn gutter_dimensions(
23745        &self,
23746        font_id: FontId,
23747        font_size: Pixels,
23748        max_line_number_width: Pixels,
23749        cx: &App,
23750    ) -> Option<GutterDimensions> {
23751        if !self.show_gutter {
23752            return None;
23753        }
23754
23755        let ch_width = cx.text_system().ch_width(font_id, font_size).log_err()?;
23756        let ch_advance = cx.text_system().ch_advance(font_id, font_size).log_err()?;
23757
23758        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
23759            matches!(
23760                ProjectSettings::get_global(cx).git.git_gutter,
23761                GitGutterSetting::TrackedFiles
23762            )
23763        });
23764        let gutter_settings = EditorSettings::get_global(cx).gutter;
23765        let show_line_numbers = self
23766            .show_line_numbers
23767            .unwrap_or(gutter_settings.line_numbers);
23768        let line_gutter_width = if show_line_numbers {
23769            // Avoid flicker-like gutter resizes when the line number gains another digit by
23770            // only resizing the gutter on files with > 10**min_line_number_digits lines.
23771            let min_width_for_number_on_gutter =
23772                ch_advance * gutter_settings.min_line_number_digits as f32;
23773            max_line_number_width.max(min_width_for_number_on_gutter)
23774        } else {
23775            0.0.into()
23776        };
23777
23778        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
23779        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
23780
23781        let git_blame_entries_width =
23782            self.git_blame_gutter_max_author_length
23783                .map(|max_author_length| {
23784                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
23785                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
23786
23787                    /// The number of characters to dedicate to gaps and margins.
23788                    const SPACING_WIDTH: usize = 4;
23789
23790                    let max_char_count = max_author_length.min(renderer.max_author_length())
23791                        + ::git::SHORT_SHA_LENGTH
23792                        + MAX_RELATIVE_TIMESTAMP.len()
23793                        + SPACING_WIDTH;
23794
23795                    ch_advance * max_char_count
23796                });
23797
23798        let is_singleton = self.buffer_snapshot().is_singleton();
23799
23800        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
23801        left_padding += if !is_singleton {
23802            ch_width * 4.0
23803        } else if show_runnables || show_breakpoints {
23804            ch_width * 3.0
23805        } else if show_git_gutter && show_line_numbers {
23806            ch_width * 2.0
23807        } else if show_git_gutter || show_line_numbers {
23808            ch_width
23809        } else {
23810            px(0.)
23811        };
23812
23813        let shows_folds = is_singleton && gutter_settings.folds;
23814
23815        let right_padding = if shows_folds && show_line_numbers {
23816            ch_width * 4.0
23817        } else if shows_folds || (!is_singleton && show_line_numbers) {
23818            ch_width * 3.0
23819        } else if show_line_numbers {
23820            ch_width
23821        } else {
23822            px(0.)
23823        };
23824
23825        Some(GutterDimensions {
23826            left_padding,
23827            right_padding,
23828            width: line_gutter_width + left_padding + right_padding,
23829            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
23830            git_blame_entries_width,
23831        })
23832    }
23833
23834    pub fn render_crease_toggle(
23835        &self,
23836        buffer_row: MultiBufferRow,
23837        row_contains_cursor: bool,
23838        editor: Entity<Editor>,
23839        window: &mut Window,
23840        cx: &mut App,
23841    ) -> Option<AnyElement> {
23842        let folded = self.is_line_folded(buffer_row);
23843        let mut is_foldable = false;
23844
23845        if let Some(crease) = self
23846            .crease_snapshot
23847            .query_row(buffer_row, self.buffer_snapshot())
23848        {
23849            is_foldable = true;
23850            match crease {
23851                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
23852                    if let Some(render_toggle) = render_toggle {
23853                        let toggle_callback =
23854                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
23855                                if folded {
23856                                    editor.update(cx, |editor, cx| {
23857                                        editor.fold_at(buffer_row, window, cx)
23858                                    });
23859                                } else {
23860                                    editor.update(cx, |editor, cx| {
23861                                        editor.unfold_at(buffer_row, window, cx)
23862                                    });
23863                                }
23864                            });
23865                        return Some((render_toggle)(
23866                            buffer_row,
23867                            folded,
23868                            toggle_callback,
23869                            window,
23870                            cx,
23871                        ));
23872                    }
23873                }
23874            }
23875        }
23876
23877        is_foldable |= self.starts_indent(buffer_row);
23878
23879        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
23880            Some(
23881                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
23882                    .toggle_state(folded)
23883                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
23884                        if folded {
23885                            this.unfold_at(buffer_row, window, cx);
23886                        } else {
23887                            this.fold_at(buffer_row, window, cx);
23888                        }
23889                    }))
23890                    .into_any_element(),
23891            )
23892        } else {
23893            None
23894        }
23895    }
23896
23897    pub fn render_crease_trailer(
23898        &self,
23899        buffer_row: MultiBufferRow,
23900        window: &mut Window,
23901        cx: &mut App,
23902    ) -> Option<AnyElement> {
23903        let folded = self.is_line_folded(buffer_row);
23904        if let Crease::Inline { render_trailer, .. } = self
23905            .crease_snapshot
23906            .query_row(buffer_row, self.buffer_snapshot())?
23907        {
23908            let render_trailer = render_trailer.as_ref()?;
23909            Some(render_trailer(buffer_row, folded, window, cx))
23910        } else {
23911            None
23912        }
23913    }
23914}
23915
23916impl Deref for EditorSnapshot {
23917    type Target = DisplaySnapshot;
23918
23919    fn deref(&self) -> &Self::Target {
23920        &self.display_snapshot
23921    }
23922}
23923
23924#[derive(Clone, Debug, PartialEq, Eq)]
23925pub enum EditorEvent {
23926    InputIgnored {
23927        text: Arc<str>,
23928    },
23929    InputHandled {
23930        utf16_range_to_replace: Option<Range<isize>>,
23931        text: Arc<str>,
23932    },
23933    ExcerptsAdded {
23934        buffer: Entity<Buffer>,
23935        predecessor: ExcerptId,
23936        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
23937    },
23938    ExcerptsRemoved {
23939        ids: Vec<ExcerptId>,
23940        removed_buffer_ids: Vec<BufferId>,
23941    },
23942    BufferFoldToggled {
23943        ids: Vec<ExcerptId>,
23944        folded: bool,
23945    },
23946    ExcerptsEdited {
23947        ids: Vec<ExcerptId>,
23948    },
23949    ExcerptsExpanded {
23950        ids: Vec<ExcerptId>,
23951    },
23952    BufferEdited,
23953    Edited {
23954        transaction_id: clock::Lamport,
23955    },
23956    Reparsed(BufferId),
23957    Focused,
23958    FocusedIn,
23959    Blurred,
23960    DirtyChanged,
23961    Saved,
23962    TitleChanged,
23963    SelectionsChanged {
23964        local: bool,
23965    },
23966    ScrollPositionChanged {
23967        local: bool,
23968        autoscroll: bool,
23969    },
23970    TransactionUndone {
23971        transaction_id: clock::Lamport,
23972    },
23973    TransactionBegun {
23974        transaction_id: clock::Lamport,
23975    },
23976    CursorShapeChanged,
23977    BreadcrumbsChanged,
23978    PushedToNavHistory {
23979        anchor: Anchor,
23980        is_deactivate: bool,
23981    },
23982}
23983
23984impl EventEmitter<EditorEvent> for Editor {}
23985
23986impl Focusable for Editor {
23987    fn focus_handle(&self, _cx: &App) -> FocusHandle {
23988        self.focus_handle.clone()
23989    }
23990}
23991
23992impl Render for Editor {
23993    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23994        let settings = ThemeSettings::get_global(cx);
23995
23996        let mut text_style = match self.mode {
23997            EditorMode::SingleLine | EditorMode::AutoHeight { .. } => TextStyle {
23998                color: cx.theme().colors().editor_foreground,
23999                font_family: settings.ui_font.family.clone(),
24000                font_features: settings.ui_font.features.clone(),
24001                font_fallbacks: settings.ui_font.fallbacks.clone(),
24002                font_size: rems(0.875).into(),
24003                font_weight: settings.ui_font.weight,
24004                line_height: relative(settings.buffer_line_height.value()),
24005                ..Default::default()
24006            },
24007            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
24008                color: cx.theme().colors().editor_foreground,
24009                font_family: settings.buffer_font.family.clone(),
24010                font_features: settings.buffer_font.features.clone(),
24011                font_fallbacks: settings.buffer_font.fallbacks.clone(),
24012                font_size: settings.buffer_font_size(cx).into(),
24013                font_weight: settings.buffer_font.weight,
24014                line_height: relative(settings.buffer_line_height.value()),
24015                ..Default::default()
24016            },
24017        };
24018        if let Some(text_style_refinement) = &self.text_style_refinement {
24019            text_style.refine(text_style_refinement)
24020        }
24021
24022        let background = match self.mode {
24023            EditorMode::SingleLine => cx.theme().system().transparent,
24024            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
24025            EditorMode::Full { .. } => cx.theme().colors().editor_background,
24026            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
24027        };
24028
24029        EditorElement::new(
24030            &cx.entity(),
24031            EditorStyle {
24032                background,
24033                border: cx.theme().colors().border,
24034                local_player: cx.theme().players().local(),
24035                text: text_style,
24036                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
24037                syntax: cx.theme().syntax().clone(),
24038                status: cx.theme().status().clone(),
24039                inlay_hints_style: make_inlay_hints_style(cx),
24040                edit_prediction_styles: make_suggestion_styles(cx),
24041                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
24042                show_underlines: self.diagnostics_enabled(),
24043            },
24044        )
24045    }
24046}
24047
24048impl EntityInputHandler for Editor {
24049    fn text_for_range(
24050        &mut self,
24051        range_utf16: Range<usize>,
24052        adjusted_range: &mut Option<Range<usize>>,
24053        _: &mut Window,
24054        cx: &mut Context<Self>,
24055    ) -> Option<String> {
24056        let snapshot = self.buffer.read(cx).read(cx);
24057        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
24058        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
24059        if (start.0..end.0) != range_utf16 {
24060            adjusted_range.replace(start.0..end.0);
24061        }
24062        Some(snapshot.text_for_range(start..end).collect())
24063    }
24064
24065    fn selected_text_range(
24066        &mut self,
24067        ignore_disabled_input: bool,
24068        _: &mut Window,
24069        cx: &mut Context<Self>,
24070    ) -> Option<UTF16Selection> {
24071        // Prevent the IME menu from appearing when holding down an alphabetic key
24072        // while input is disabled.
24073        if !ignore_disabled_input && !self.input_enabled {
24074            return None;
24075        }
24076
24077        let selection = self
24078            .selections
24079            .newest::<OffsetUtf16>(&self.display_snapshot(cx));
24080        let range = selection.range();
24081
24082        Some(UTF16Selection {
24083            range: range.start.0..range.end.0,
24084            reversed: selection.reversed,
24085        })
24086    }
24087
24088    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
24089        let snapshot = self.buffer.read(cx).read(cx);
24090        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
24091        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
24092    }
24093
24094    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
24095        self.clear_highlights::<InputComposition>(cx);
24096        self.ime_transaction.take();
24097    }
24098
24099    fn replace_text_in_range(
24100        &mut self,
24101        range_utf16: Option<Range<usize>>,
24102        text: &str,
24103        window: &mut Window,
24104        cx: &mut Context<Self>,
24105    ) {
24106        if !self.input_enabled {
24107            cx.emit(EditorEvent::InputIgnored { text: text.into() });
24108            return;
24109        }
24110
24111        self.transact(window, cx, |this, window, cx| {
24112            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
24113                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
24114                Some(this.selection_replacement_ranges(range_utf16, cx))
24115            } else {
24116                this.marked_text_ranges(cx)
24117            };
24118
24119            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
24120                let newest_selection_id = this.selections.newest_anchor().id;
24121                this.selections
24122                    .all::<OffsetUtf16>(&this.display_snapshot(cx))
24123                    .iter()
24124                    .zip(ranges_to_replace.iter())
24125                    .find_map(|(selection, range)| {
24126                        if selection.id == newest_selection_id {
24127                            Some(
24128                                (range.start.0 as isize - selection.head().0 as isize)
24129                                    ..(range.end.0 as isize - selection.head().0 as isize),
24130                            )
24131                        } else {
24132                            None
24133                        }
24134                    })
24135            });
24136
24137            cx.emit(EditorEvent::InputHandled {
24138                utf16_range_to_replace: range_to_replace,
24139                text: text.into(),
24140            });
24141
24142            if let Some(new_selected_ranges) = new_selected_ranges {
24143                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
24144                    selections.select_ranges(new_selected_ranges)
24145                });
24146                this.backspace(&Default::default(), window, cx);
24147            }
24148
24149            this.handle_input(text, window, cx);
24150        });
24151
24152        if let Some(transaction) = self.ime_transaction {
24153            self.buffer.update(cx, |buffer, cx| {
24154                buffer.group_until_transaction(transaction, cx);
24155            });
24156        }
24157
24158        self.unmark_text(window, cx);
24159    }
24160
24161    fn replace_and_mark_text_in_range(
24162        &mut self,
24163        range_utf16: Option<Range<usize>>,
24164        text: &str,
24165        new_selected_range_utf16: Option<Range<usize>>,
24166        window: &mut Window,
24167        cx: &mut Context<Self>,
24168    ) {
24169        if !self.input_enabled {
24170            return;
24171        }
24172
24173        let transaction = self.transact(window, cx, |this, window, cx| {
24174            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
24175                let snapshot = this.buffer.read(cx).read(cx);
24176                if let Some(relative_range_utf16) = range_utf16.as_ref() {
24177                    for marked_range in &mut marked_ranges {
24178                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
24179                        marked_range.start.0 += relative_range_utf16.start;
24180                        marked_range.start =
24181                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
24182                        marked_range.end =
24183                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
24184                    }
24185                }
24186                Some(marked_ranges)
24187            } else if let Some(range_utf16) = range_utf16 {
24188                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
24189                Some(this.selection_replacement_ranges(range_utf16, cx))
24190            } else {
24191                None
24192            };
24193
24194            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
24195                let newest_selection_id = this.selections.newest_anchor().id;
24196                this.selections
24197                    .all::<OffsetUtf16>(&this.display_snapshot(cx))
24198                    .iter()
24199                    .zip(ranges_to_replace.iter())
24200                    .find_map(|(selection, range)| {
24201                        if selection.id == newest_selection_id {
24202                            Some(
24203                                (range.start.0 as isize - selection.head().0 as isize)
24204                                    ..(range.end.0 as isize - selection.head().0 as isize),
24205                            )
24206                        } else {
24207                            None
24208                        }
24209                    })
24210            });
24211
24212            cx.emit(EditorEvent::InputHandled {
24213                utf16_range_to_replace: range_to_replace,
24214                text: text.into(),
24215            });
24216
24217            if let Some(ranges) = ranges_to_replace {
24218                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
24219                    s.select_ranges(ranges)
24220                });
24221            }
24222
24223            let marked_ranges = {
24224                let snapshot = this.buffer.read(cx).read(cx);
24225                this.selections
24226                    .disjoint_anchors_arc()
24227                    .iter()
24228                    .map(|selection| {
24229                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
24230                    })
24231                    .collect::<Vec<_>>()
24232            };
24233
24234            if text.is_empty() {
24235                this.unmark_text(window, cx);
24236            } else {
24237                this.highlight_text::<InputComposition>(
24238                    marked_ranges.clone(),
24239                    HighlightStyle {
24240                        underline: Some(UnderlineStyle {
24241                            thickness: px(1.),
24242                            color: None,
24243                            wavy: false,
24244                        }),
24245                        ..Default::default()
24246                    },
24247                    cx,
24248                );
24249            }
24250
24251            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
24252            let use_autoclose = this.use_autoclose;
24253            let use_auto_surround = this.use_auto_surround;
24254            this.set_use_autoclose(false);
24255            this.set_use_auto_surround(false);
24256            this.handle_input(text, window, cx);
24257            this.set_use_autoclose(use_autoclose);
24258            this.set_use_auto_surround(use_auto_surround);
24259
24260            if let Some(new_selected_range) = new_selected_range_utf16 {
24261                let snapshot = this.buffer.read(cx).read(cx);
24262                let new_selected_ranges = marked_ranges
24263                    .into_iter()
24264                    .map(|marked_range| {
24265                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
24266                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
24267                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
24268                        snapshot.clip_offset_utf16(new_start, Bias::Left)
24269                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
24270                    })
24271                    .collect::<Vec<_>>();
24272
24273                drop(snapshot);
24274                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
24275                    selections.select_ranges(new_selected_ranges)
24276                });
24277            }
24278        });
24279
24280        self.ime_transaction = self.ime_transaction.or(transaction);
24281        if let Some(transaction) = self.ime_transaction {
24282            self.buffer.update(cx, |buffer, cx| {
24283                buffer.group_until_transaction(transaction, cx);
24284            });
24285        }
24286
24287        if self.text_highlights::<InputComposition>(cx).is_none() {
24288            self.ime_transaction.take();
24289        }
24290    }
24291
24292    fn bounds_for_range(
24293        &mut self,
24294        range_utf16: Range<usize>,
24295        element_bounds: gpui::Bounds<Pixels>,
24296        window: &mut Window,
24297        cx: &mut Context<Self>,
24298    ) -> Option<gpui::Bounds<Pixels>> {
24299        let text_layout_details = self.text_layout_details(window);
24300        let CharacterDimensions {
24301            em_width,
24302            em_advance,
24303            line_height,
24304        } = self.character_dimensions(window);
24305
24306        let snapshot = self.snapshot(window, cx);
24307        let scroll_position = snapshot.scroll_position();
24308        let scroll_left = scroll_position.x * ScrollOffset::from(em_advance);
24309
24310        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
24311        let x = Pixels::from(
24312            ScrollOffset::from(
24313                snapshot.x_for_display_point(start, &text_layout_details)
24314                    + self.gutter_dimensions.full_width(),
24315            ) - scroll_left,
24316        );
24317        let y = line_height * (start.row().as_f64() - scroll_position.y) as f32;
24318
24319        Some(Bounds {
24320            origin: element_bounds.origin + point(x, y),
24321            size: size(em_width, line_height),
24322        })
24323    }
24324
24325    fn character_index_for_point(
24326        &mut self,
24327        point: gpui::Point<Pixels>,
24328        _window: &mut Window,
24329        _cx: &mut Context<Self>,
24330    ) -> Option<usize> {
24331        let position_map = self.last_position_map.as_ref()?;
24332        if !position_map.text_hitbox.contains(&point) {
24333            return None;
24334        }
24335        let display_point = position_map.point_for_position(point).previous_valid;
24336        let anchor = position_map
24337            .snapshot
24338            .display_point_to_anchor(display_point, Bias::Left);
24339        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot());
24340        Some(utf16_offset.0)
24341    }
24342
24343    fn accepts_text_input(&self, _window: &mut Window, _cx: &mut Context<Self>) -> bool {
24344        self.input_enabled
24345    }
24346}
24347
24348trait SelectionExt {
24349    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
24350    fn spanned_rows(
24351        &self,
24352        include_end_if_at_line_start: bool,
24353        map: &DisplaySnapshot,
24354    ) -> Range<MultiBufferRow>;
24355}
24356
24357impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
24358    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
24359        let start = self
24360            .start
24361            .to_point(map.buffer_snapshot())
24362            .to_display_point(map);
24363        let end = self
24364            .end
24365            .to_point(map.buffer_snapshot())
24366            .to_display_point(map);
24367        if self.reversed {
24368            end..start
24369        } else {
24370            start..end
24371        }
24372    }
24373
24374    fn spanned_rows(
24375        &self,
24376        include_end_if_at_line_start: bool,
24377        map: &DisplaySnapshot,
24378    ) -> Range<MultiBufferRow> {
24379        let start = self.start.to_point(map.buffer_snapshot());
24380        let mut end = self.end.to_point(map.buffer_snapshot());
24381        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
24382            end.row -= 1;
24383        }
24384
24385        let buffer_start = map.prev_line_boundary(start).0;
24386        let buffer_end = map.next_line_boundary(end).0;
24387        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
24388    }
24389}
24390
24391impl<T: InvalidationRegion> InvalidationStack<T> {
24392    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
24393    where
24394        S: Clone + ToOffset,
24395    {
24396        while let Some(region) = self.last() {
24397            let all_selections_inside_invalidation_ranges =
24398                if selections.len() == region.ranges().len() {
24399                    selections
24400                        .iter()
24401                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
24402                        .all(|(selection, invalidation_range)| {
24403                            let head = selection.head().to_offset(buffer);
24404                            invalidation_range.start <= head && invalidation_range.end >= head
24405                        })
24406                } else {
24407                    false
24408                };
24409
24410            if all_selections_inside_invalidation_ranges {
24411                break;
24412            } else {
24413                self.pop();
24414            }
24415        }
24416    }
24417}
24418
24419impl<T> Default for InvalidationStack<T> {
24420    fn default() -> Self {
24421        Self(Default::default())
24422    }
24423}
24424
24425impl<T> Deref for InvalidationStack<T> {
24426    type Target = Vec<T>;
24427
24428    fn deref(&self) -> &Self::Target {
24429        &self.0
24430    }
24431}
24432
24433impl<T> DerefMut for InvalidationStack<T> {
24434    fn deref_mut(&mut self) -> &mut Self::Target {
24435        &mut self.0
24436    }
24437}
24438
24439impl InvalidationRegion for SnippetState {
24440    fn ranges(&self) -> &[Range<Anchor>] {
24441        &self.ranges[self.active_index]
24442    }
24443}
24444
24445fn edit_prediction_edit_text(
24446    current_snapshot: &BufferSnapshot,
24447    edits: &[(Range<Anchor>, impl AsRef<str>)],
24448    edit_preview: &EditPreview,
24449    include_deletions: bool,
24450    cx: &App,
24451) -> HighlightedText {
24452    let edits = edits
24453        .iter()
24454        .map(|(anchor, text)| (anchor.start.text_anchor..anchor.end.text_anchor, text))
24455        .collect::<Vec<_>>();
24456
24457    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
24458}
24459
24460fn edit_prediction_fallback_text(edits: &[(Range<Anchor>, Arc<str>)], cx: &App) -> HighlightedText {
24461    // Fallback for providers that don't provide edit_preview (like Copilot/Supermaven)
24462    // Just show the raw edit text with basic styling
24463    let mut text = String::new();
24464    let mut highlights = Vec::new();
24465
24466    let insertion_highlight_style = HighlightStyle {
24467        color: Some(cx.theme().colors().text),
24468        ..Default::default()
24469    };
24470
24471    for (_, edit_text) in edits {
24472        let start_offset = text.len();
24473        text.push_str(edit_text);
24474        let end_offset = text.len();
24475
24476        if start_offset < end_offset {
24477            highlights.push((start_offset..end_offset, insertion_highlight_style));
24478        }
24479    }
24480
24481    HighlightedText {
24482        text: text.into(),
24483        highlights,
24484    }
24485}
24486
24487pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
24488    match severity {
24489        lsp::DiagnosticSeverity::ERROR => colors.error,
24490        lsp::DiagnosticSeverity::WARNING => colors.warning,
24491        lsp::DiagnosticSeverity::INFORMATION => colors.info,
24492        lsp::DiagnosticSeverity::HINT => colors.info,
24493        _ => colors.ignored,
24494    }
24495}
24496
24497pub fn styled_runs_for_code_label<'a>(
24498    label: &'a CodeLabel,
24499    syntax_theme: &'a theme::SyntaxTheme,
24500) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
24501    let fade_out = HighlightStyle {
24502        fade_out: Some(0.35),
24503        ..Default::default()
24504    };
24505
24506    let mut prev_end = label.filter_range.end;
24507    label
24508        .runs
24509        .iter()
24510        .enumerate()
24511        .flat_map(move |(ix, (range, highlight_id))| {
24512            let style = if let Some(style) = highlight_id.style(syntax_theme) {
24513                style
24514            } else {
24515                return Default::default();
24516            };
24517            let muted_style = style.highlight(fade_out);
24518
24519            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
24520            if range.start >= label.filter_range.end {
24521                if range.start > prev_end {
24522                    runs.push((prev_end..range.start, fade_out));
24523                }
24524                runs.push((range.clone(), muted_style));
24525            } else if range.end <= label.filter_range.end {
24526                runs.push((range.clone(), style));
24527            } else {
24528                runs.push((range.start..label.filter_range.end, style));
24529                runs.push((label.filter_range.end..range.end, muted_style));
24530            }
24531            prev_end = cmp::max(prev_end, range.end);
24532
24533            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
24534                runs.push((prev_end..label.text.len(), fade_out));
24535            }
24536
24537            runs
24538        })
24539}
24540
24541pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
24542    let mut prev_index = 0;
24543    let mut prev_codepoint: Option<char> = None;
24544    text.char_indices()
24545        .chain([(text.len(), '\0')])
24546        .filter_map(move |(index, codepoint)| {
24547            let prev_codepoint = prev_codepoint.replace(codepoint)?;
24548            let is_boundary = index == text.len()
24549                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
24550                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
24551            if is_boundary {
24552                let chunk = &text[prev_index..index];
24553                prev_index = index;
24554                Some(chunk)
24555            } else {
24556                None
24557            }
24558        })
24559}
24560
24561pub trait RangeToAnchorExt: Sized {
24562    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
24563
24564    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
24565        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot());
24566        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
24567    }
24568}
24569
24570impl<T: ToOffset> RangeToAnchorExt for Range<T> {
24571    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
24572        let start_offset = self.start.to_offset(snapshot);
24573        let end_offset = self.end.to_offset(snapshot);
24574        if start_offset == end_offset {
24575            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
24576        } else {
24577            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
24578        }
24579    }
24580}
24581
24582pub trait RowExt {
24583    fn as_f64(&self) -> f64;
24584
24585    fn next_row(&self) -> Self;
24586
24587    fn previous_row(&self) -> Self;
24588
24589    fn minus(&self, other: Self) -> u32;
24590}
24591
24592impl RowExt for DisplayRow {
24593    fn as_f64(&self) -> f64 {
24594        self.0 as _
24595    }
24596
24597    fn next_row(&self) -> Self {
24598        Self(self.0 + 1)
24599    }
24600
24601    fn previous_row(&self) -> Self {
24602        Self(self.0.saturating_sub(1))
24603    }
24604
24605    fn minus(&self, other: Self) -> u32 {
24606        self.0 - other.0
24607    }
24608}
24609
24610impl RowExt for MultiBufferRow {
24611    fn as_f64(&self) -> f64 {
24612        self.0 as _
24613    }
24614
24615    fn next_row(&self) -> Self {
24616        Self(self.0 + 1)
24617    }
24618
24619    fn previous_row(&self) -> Self {
24620        Self(self.0.saturating_sub(1))
24621    }
24622
24623    fn minus(&self, other: Self) -> u32 {
24624        self.0 - other.0
24625    }
24626}
24627
24628trait RowRangeExt {
24629    type Row;
24630
24631    fn len(&self) -> usize;
24632
24633    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
24634}
24635
24636impl RowRangeExt for Range<MultiBufferRow> {
24637    type Row = MultiBufferRow;
24638
24639    fn len(&self) -> usize {
24640        (self.end.0 - self.start.0) as usize
24641    }
24642
24643    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
24644        (self.start.0..self.end.0).map(MultiBufferRow)
24645    }
24646}
24647
24648impl RowRangeExt for Range<DisplayRow> {
24649    type Row = DisplayRow;
24650
24651    fn len(&self) -> usize {
24652        (self.end.0 - self.start.0) as usize
24653    }
24654
24655    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
24656        (self.start.0..self.end.0).map(DisplayRow)
24657    }
24658}
24659
24660/// If select range has more than one line, we
24661/// just point the cursor to range.start.
24662fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
24663    if range.start.row == range.end.row {
24664        range
24665    } else {
24666        range.start..range.start
24667    }
24668}
24669pub struct KillRing(ClipboardItem);
24670impl Global for KillRing {}
24671
24672const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
24673
24674enum BreakpointPromptEditAction {
24675    Log,
24676    Condition,
24677    HitCondition,
24678}
24679
24680struct BreakpointPromptEditor {
24681    pub(crate) prompt: Entity<Editor>,
24682    editor: WeakEntity<Editor>,
24683    breakpoint_anchor: Anchor,
24684    breakpoint: Breakpoint,
24685    edit_action: BreakpointPromptEditAction,
24686    block_ids: HashSet<CustomBlockId>,
24687    editor_margins: Arc<Mutex<EditorMargins>>,
24688    _subscriptions: Vec<Subscription>,
24689}
24690
24691impl BreakpointPromptEditor {
24692    const MAX_LINES: u8 = 4;
24693
24694    fn new(
24695        editor: WeakEntity<Editor>,
24696        breakpoint_anchor: Anchor,
24697        breakpoint: Breakpoint,
24698        edit_action: BreakpointPromptEditAction,
24699        window: &mut Window,
24700        cx: &mut Context<Self>,
24701    ) -> Self {
24702        let base_text = match edit_action {
24703            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
24704            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
24705            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
24706        }
24707        .map(|msg| msg.to_string())
24708        .unwrap_or_default();
24709
24710        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
24711        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
24712
24713        let prompt = cx.new(|cx| {
24714            let mut prompt = Editor::new(
24715                EditorMode::AutoHeight {
24716                    min_lines: 1,
24717                    max_lines: Some(Self::MAX_LINES as usize),
24718                },
24719                buffer,
24720                None,
24721                window,
24722                cx,
24723            );
24724            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
24725            prompt.set_show_cursor_when_unfocused(false, cx);
24726            prompt.set_placeholder_text(
24727                match edit_action {
24728                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
24729                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
24730                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
24731                },
24732                window,
24733                cx,
24734            );
24735
24736            prompt
24737        });
24738
24739        Self {
24740            prompt,
24741            editor,
24742            breakpoint_anchor,
24743            breakpoint,
24744            edit_action,
24745            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
24746            block_ids: Default::default(),
24747            _subscriptions: vec![],
24748        }
24749    }
24750
24751    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
24752        self.block_ids.extend(block_ids)
24753    }
24754
24755    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
24756        if let Some(editor) = self.editor.upgrade() {
24757            let message = self
24758                .prompt
24759                .read(cx)
24760                .buffer
24761                .read(cx)
24762                .as_singleton()
24763                .expect("A multi buffer in breakpoint prompt isn't possible")
24764                .read(cx)
24765                .as_rope()
24766                .to_string();
24767
24768            editor.update(cx, |editor, cx| {
24769                editor.edit_breakpoint_at_anchor(
24770                    self.breakpoint_anchor,
24771                    self.breakpoint.clone(),
24772                    match self.edit_action {
24773                        BreakpointPromptEditAction::Log => {
24774                            BreakpointEditAction::EditLogMessage(message.into())
24775                        }
24776                        BreakpointPromptEditAction::Condition => {
24777                            BreakpointEditAction::EditCondition(message.into())
24778                        }
24779                        BreakpointPromptEditAction::HitCondition => {
24780                            BreakpointEditAction::EditHitCondition(message.into())
24781                        }
24782                    },
24783                    cx,
24784                );
24785
24786                editor.remove_blocks(self.block_ids.clone(), None, cx);
24787                cx.focus_self(window);
24788            });
24789        }
24790    }
24791
24792    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
24793        self.editor
24794            .update(cx, |editor, cx| {
24795                editor.remove_blocks(self.block_ids.clone(), None, cx);
24796                window.focus(&editor.focus_handle);
24797            })
24798            .log_err();
24799    }
24800
24801    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
24802        let settings = ThemeSettings::get_global(cx);
24803        let text_style = TextStyle {
24804            color: if self.prompt.read(cx).read_only(cx) {
24805                cx.theme().colors().text_disabled
24806            } else {
24807                cx.theme().colors().text
24808            },
24809            font_family: settings.buffer_font.family.clone(),
24810            font_fallbacks: settings.buffer_font.fallbacks.clone(),
24811            font_size: settings.buffer_font_size(cx).into(),
24812            font_weight: settings.buffer_font.weight,
24813            line_height: relative(settings.buffer_line_height.value()),
24814            ..Default::default()
24815        };
24816        EditorElement::new(
24817            &self.prompt,
24818            EditorStyle {
24819                background: cx.theme().colors().editor_background,
24820                local_player: cx.theme().players().local(),
24821                text: text_style,
24822                ..Default::default()
24823            },
24824        )
24825    }
24826}
24827
24828impl Render for BreakpointPromptEditor {
24829    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
24830        let editor_margins = *self.editor_margins.lock();
24831        let gutter_dimensions = editor_margins.gutter;
24832        h_flex()
24833            .key_context("Editor")
24834            .bg(cx.theme().colors().editor_background)
24835            .border_y_1()
24836            .border_color(cx.theme().status().info_border)
24837            .size_full()
24838            .py(window.line_height() / 2.5)
24839            .on_action(cx.listener(Self::confirm))
24840            .on_action(cx.listener(Self::cancel))
24841            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
24842            .child(div().flex_1().child(self.render_prompt_editor(cx)))
24843    }
24844}
24845
24846impl Focusable for BreakpointPromptEditor {
24847    fn focus_handle(&self, cx: &App) -> FocusHandle {
24848        self.prompt.focus_handle(cx)
24849    }
24850}
24851
24852fn all_edits_insertions_or_deletions(
24853    edits: &Vec<(Range<Anchor>, Arc<str>)>,
24854    snapshot: &MultiBufferSnapshot,
24855) -> bool {
24856    let mut all_insertions = true;
24857    let mut all_deletions = true;
24858
24859    for (range, new_text) in edits.iter() {
24860        let range_is_empty = range.to_offset(snapshot).is_empty();
24861        let text_is_empty = new_text.is_empty();
24862
24863        if range_is_empty != text_is_empty {
24864            if range_is_empty {
24865                all_deletions = false;
24866            } else {
24867                all_insertions = false;
24868            }
24869        } else {
24870            return false;
24871        }
24872
24873        if !all_insertions && !all_deletions {
24874            return false;
24875        }
24876    }
24877    all_insertions || all_deletions
24878}
24879
24880struct MissingEditPredictionKeybindingTooltip;
24881
24882impl Render for MissingEditPredictionKeybindingTooltip {
24883    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
24884        ui::tooltip_container(cx, |container, cx| {
24885            container
24886                .flex_shrink_0()
24887                .max_w_80()
24888                .min_h(rems_from_px(124.))
24889                .justify_between()
24890                .child(
24891                    v_flex()
24892                        .flex_1()
24893                        .text_ui_sm(cx)
24894                        .child(Label::new("Conflict with Accept Keybinding"))
24895                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
24896                )
24897                .child(
24898                    h_flex()
24899                        .pb_1()
24900                        .gap_1()
24901                        .items_end()
24902                        .w_full()
24903                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
24904                            window.dispatch_action(zed_actions::OpenKeymapFile.boxed_clone(), cx)
24905                        }))
24906                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
24907                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
24908                        })),
24909                )
24910        })
24911    }
24912}
24913
24914#[derive(Debug, Clone, Copy, PartialEq)]
24915pub struct LineHighlight {
24916    pub background: Background,
24917    pub border: Option<gpui::Hsla>,
24918    pub include_gutter: bool,
24919    pub type_id: Option<TypeId>,
24920}
24921
24922struct LineManipulationResult {
24923    pub new_text: String,
24924    pub line_count_before: usize,
24925    pub line_count_after: usize,
24926}
24927
24928fn render_diff_hunk_controls(
24929    row: u32,
24930    status: &DiffHunkStatus,
24931    hunk_range: Range<Anchor>,
24932    is_created_file: bool,
24933    line_height: Pixels,
24934    editor: &Entity<Editor>,
24935    _window: &mut Window,
24936    cx: &mut App,
24937) -> AnyElement {
24938    h_flex()
24939        .h(line_height)
24940        .mr_1()
24941        .gap_1()
24942        .px_0p5()
24943        .pb_1()
24944        .border_x_1()
24945        .border_b_1()
24946        .border_color(cx.theme().colors().border_variant)
24947        .rounded_b_lg()
24948        .bg(cx.theme().colors().editor_background)
24949        .gap_1()
24950        .block_mouse_except_scroll()
24951        .shadow_md()
24952        .child(if status.has_secondary_hunk() {
24953            Button::new(("stage", row as u64), "Stage")
24954                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
24955                .tooltip({
24956                    let focus_handle = editor.focus_handle(cx);
24957                    move |_window, cx| {
24958                        Tooltip::for_action_in(
24959                            "Stage Hunk",
24960                            &::git::ToggleStaged,
24961                            &focus_handle,
24962                            cx,
24963                        )
24964                    }
24965                })
24966                .on_click({
24967                    let editor = editor.clone();
24968                    move |_event, _window, cx| {
24969                        editor.update(cx, |editor, cx| {
24970                            editor.stage_or_unstage_diff_hunks(
24971                                true,
24972                                vec![hunk_range.start..hunk_range.start],
24973                                cx,
24974                            );
24975                        });
24976                    }
24977                })
24978        } else {
24979            Button::new(("unstage", row as u64), "Unstage")
24980                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
24981                .tooltip({
24982                    let focus_handle = editor.focus_handle(cx);
24983                    move |_window, cx| {
24984                        Tooltip::for_action_in(
24985                            "Unstage Hunk",
24986                            &::git::ToggleStaged,
24987                            &focus_handle,
24988                            cx,
24989                        )
24990                    }
24991                })
24992                .on_click({
24993                    let editor = editor.clone();
24994                    move |_event, _window, cx| {
24995                        editor.update(cx, |editor, cx| {
24996                            editor.stage_or_unstage_diff_hunks(
24997                                false,
24998                                vec![hunk_range.start..hunk_range.start],
24999                                cx,
25000                            );
25001                        });
25002                    }
25003                })
25004        })
25005        .child(
25006            Button::new(("restore", row as u64), "Restore")
25007                .tooltip({
25008                    let focus_handle = editor.focus_handle(cx);
25009                    move |_window, cx| {
25010                        Tooltip::for_action_in("Restore Hunk", &::git::Restore, &focus_handle, cx)
25011                    }
25012                })
25013                .on_click({
25014                    let editor = editor.clone();
25015                    move |_event, window, cx| {
25016                        editor.update(cx, |editor, cx| {
25017                            let snapshot = editor.snapshot(window, cx);
25018                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot());
25019                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
25020                        });
25021                    }
25022                })
25023                .disabled(is_created_file),
25024        )
25025        .when(
25026            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
25027            |el| {
25028                el.child(
25029                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
25030                        .shape(IconButtonShape::Square)
25031                        .icon_size(IconSize::Small)
25032                        // .disabled(!has_multiple_hunks)
25033                        .tooltip({
25034                            let focus_handle = editor.focus_handle(cx);
25035                            move |_window, cx| {
25036                                Tooltip::for_action_in("Next Hunk", &GoToHunk, &focus_handle, cx)
25037                            }
25038                        })
25039                        .on_click({
25040                            let editor = editor.clone();
25041                            move |_event, window, cx| {
25042                                editor.update(cx, |editor, cx| {
25043                                    let snapshot = editor.snapshot(window, cx);
25044                                    let position =
25045                                        hunk_range.end.to_point(&snapshot.buffer_snapshot());
25046                                    editor.go_to_hunk_before_or_after_position(
25047                                        &snapshot,
25048                                        position,
25049                                        Direction::Next,
25050                                        window,
25051                                        cx,
25052                                    );
25053                                    editor.expand_selected_diff_hunks(cx);
25054                                });
25055                            }
25056                        }),
25057                )
25058                .child(
25059                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
25060                        .shape(IconButtonShape::Square)
25061                        .icon_size(IconSize::Small)
25062                        // .disabled(!has_multiple_hunks)
25063                        .tooltip({
25064                            let focus_handle = editor.focus_handle(cx);
25065                            move |_window, cx| {
25066                                Tooltip::for_action_in(
25067                                    "Previous Hunk",
25068                                    &GoToPreviousHunk,
25069                                    &focus_handle,
25070                                    cx,
25071                                )
25072                            }
25073                        })
25074                        .on_click({
25075                            let editor = editor.clone();
25076                            move |_event, window, cx| {
25077                                editor.update(cx, |editor, cx| {
25078                                    let snapshot = editor.snapshot(window, cx);
25079                                    let point =
25080                                        hunk_range.start.to_point(&snapshot.buffer_snapshot());
25081                                    editor.go_to_hunk_before_or_after_position(
25082                                        &snapshot,
25083                                        point,
25084                                        Direction::Prev,
25085                                        window,
25086                                        cx,
25087                                    );
25088                                    editor.expand_selected_diff_hunks(cx);
25089                                });
25090                            }
25091                        }),
25092                )
25093            },
25094        )
25095        .into_any_element()
25096}
25097
25098pub fn multibuffer_context_lines(cx: &App) -> u32 {
25099    EditorSettings::try_get(cx)
25100        .map(|settings| settings.excerpt_context_lines)
25101        .unwrap_or(2)
25102        .min(32)
25103}