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, AhoCorasickBuilder, BuildError};
   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    select_next_is_case_sensitive: Option<bool>,
 1194    pub lookup_key: Option<Box<dyn Any + Send + Sync>>,
 1195}
 1196
 1197fn debounce_value(debounce_ms: u64) -> Option<Duration> {
 1198    if debounce_ms > 0 {
 1199        Some(Duration::from_millis(debounce_ms))
 1200    } else {
 1201        None
 1202    }
 1203}
 1204
 1205#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1206enum NextScrollCursorCenterTopBottom {
 1207    #[default]
 1208    Center,
 1209    Top,
 1210    Bottom,
 1211}
 1212
 1213impl NextScrollCursorCenterTopBottom {
 1214    fn next(&self) -> Self {
 1215        match self {
 1216            Self::Center => Self::Top,
 1217            Self::Top => Self::Bottom,
 1218            Self::Bottom => Self::Center,
 1219        }
 1220    }
 1221}
 1222
 1223#[derive(Clone)]
 1224pub struct EditorSnapshot {
 1225    pub mode: EditorMode,
 1226    show_gutter: bool,
 1227    show_line_numbers: Option<bool>,
 1228    show_git_diff_gutter: Option<bool>,
 1229    show_code_actions: Option<bool>,
 1230    show_runnables: Option<bool>,
 1231    show_breakpoints: Option<bool>,
 1232    git_blame_gutter_max_author_length: Option<usize>,
 1233    pub display_snapshot: DisplaySnapshot,
 1234    pub placeholder_display_snapshot: Option<DisplaySnapshot>,
 1235    is_focused: bool,
 1236    scroll_anchor: ScrollAnchor,
 1237    ongoing_scroll: OngoingScroll,
 1238    current_line_highlight: CurrentLineHighlight,
 1239    gutter_hovered: bool,
 1240}
 1241
 1242#[derive(Default, Debug, Clone, Copy)]
 1243pub struct GutterDimensions {
 1244    pub left_padding: Pixels,
 1245    pub right_padding: Pixels,
 1246    pub width: Pixels,
 1247    pub margin: Pixels,
 1248    pub git_blame_entries_width: Option<Pixels>,
 1249}
 1250
 1251impl GutterDimensions {
 1252    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1253        Self {
 1254            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1255            ..Default::default()
 1256        }
 1257    }
 1258
 1259    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1260        -cx.text_system().descent(font_id, font_size)
 1261    }
 1262    /// The full width of the space taken up by the gutter.
 1263    pub fn full_width(&self) -> Pixels {
 1264        self.margin + self.width
 1265    }
 1266
 1267    /// The width of the space reserved for the fold indicators,
 1268    /// use alongside 'justify_end' and `gutter_width` to
 1269    /// right align content with the line numbers
 1270    pub fn fold_area_width(&self) -> Pixels {
 1271        self.margin + self.right_padding
 1272    }
 1273}
 1274
 1275struct CharacterDimensions {
 1276    em_width: Pixels,
 1277    em_advance: Pixels,
 1278    line_height: Pixels,
 1279}
 1280
 1281#[derive(Debug)]
 1282pub struct RemoteSelection {
 1283    pub replica_id: ReplicaId,
 1284    pub selection: Selection<Anchor>,
 1285    pub cursor_shape: CursorShape,
 1286    pub collaborator_id: CollaboratorId,
 1287    pub line_mode: bool,
 1288    pub user_name: Option<SharedString>,
 1289    pub color: PlayerColor,
 1290}
 1291
 1292#[derive(Clone, Debug)]
 1293struct SelectionHistoryEntry {
 1294    selections: Arc<[Selection<Anchor>]>,
 1295    select_next_state: Option<SelectNextState>,
 1296    select_prev_state: Option<SelectNextState>,
 1297    add_selections_state: Option<AddSelectionsState>,
 1298}
 1299
 1300#[derive(Copy, Clone, Debug, PartialEq, Eq)]
 1301enum SelectionHistoryMode {
 1302    Normal,
 1303    Undoing,
 1304    Redoing,
 1305    Skipping,
 1306}
 1307
 1308#[derive(Clone, PartialEq, Eq, Hash)]
 1309struct HoveredCursor {
 1310    replica_id: ReplicaId,
 1311    selection_id: usize,
 1312}
 1313
 1314impl Default for SelectionHistoryMode {
 1315    fn default() -> Self {
 1316        Self::Normal
 1317    }
 1318}
 1319
 1320#[derive(Debug)]
 1321/// SelectionEffects controls the side-effects of updating the selection.
 1322///
 1323/// The default behaviour does "what you mostly want":
 1324/// - it pushes to the nav history if the cursor moved by >10 lines
 1325/// - it re-triggers completion requests
 1326/// - it scrolls to fit
 1327///
 1328/// You might want to modify these behaviours. For example when doing a "jump"
 1329/// like go to definition, we always want to add to nav history; but when scrolling
 1330/// in vim mode we never do.
 1331///
 1332/// Similarly, you might want to disable scrolling if you don't want the viewport to
 1333/// move.
 1334#[derive(Clone)]
 1335pub struct SelectionEffects {
 1336    nav_history: Option<bool>,
 1337    completions: bool,
 1338    scroll: Option<Autoscroll>,
 1339}
 1340
 1341impl Default for SelectionEffects {
 1342    fn default() -> Self {
 1343        Self {
 1344            nav_history: None,
 1345            completions: true,
 1346            scroll: Some(Autoscroll::fit()),
 1347        }
 1348    }
 1349}
 1350impl SelectionEffects {
 1351    pub fn scroll(scroll: Autoscroll) -> Self {
 1352        Self {
 1353            scroll: Some(scroll),
 1354            ..Default::default()
 1355        }
 1356    }
 1357
 1358    pub fn no_scroll() -> Self {
 1359        Self {
 1360            scroll: None,
 1361            ..Default::default()
 1362        }
 1363    }
 1364
 1365    pub fn completions(self, completions: bool) -> Self {
 1366        Self {
 1367            completions,
 1368            ..self
 1369        }
 1370    }
 1371
 1372    pub fn nav_history(self, nav_history: bool) -> Self {
 1373        Self {
 1374            nav_history: Some(nav_history),
 1375            ..self
 1376        }
 1377    }
 1378}
 1379
 1380struct DeferredSelectionEffectsState {
 1381    changed: bool,
 1382    effects: SelectionEffects,
 1383    old_cursor_position: Anchor,
 1384    history_entry: SelectionHistoryEntry,
 1385}
 1386
 1387#[derive(Default)]
 1388struct SelectionHistory {
 1389    #[allow(clippy::type_complexity)]
 1390    selections_by_transaction:
 1391        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1392    mode: SelectionHistoryMode,
 1393    undo_stack: VecDeque<SelectionHistoryEntry>,
 1394    redo_stack: VecDeque<SelectionHistoryEntry>,
 1395}
 1396
 1397impl SelectionHistory {
 1398    #[track_caller]
 1399    fn insert_transaction(
 1400        &mut self,
 1401        transaction_id: TransactionId,
 1402        selections: Arc<[Selection<Anchor>]>,
 1403    ) {
 1404        if selections.is_empty() {
 1405            log::error!(
 1406                "SelectionHistory::insert_transaction called with empty selections. Caller: {}",
 1407                std::panic::Location::caller()
 1408            );
 1409            return;
 1410        }
 1411        self.selections_by_transaction
 1412            .insert(transaction_id, (selections, None));
 1413    }
 1414
 1415    #[allow(clippy::type_complexity)]
 1416    fn transaction(
 1417        &self,
 1418        transaction_id: TransactionId,
 1419    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1420        self.selections_by_transaction.get(&transaction_id)
 1421    }
 1422
 1423    #[allow(clippy::type_complexity)]
 1424    fn transaction_mut(
 1425        &mut self,
 1426        transaction_id: TransactionId,
 1427    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1428        self.selections_by_transaction.get_mut(&transaction_id)
 1429    }
 1430
 1431    fn push(&mut self, entry: SelectionHistoryEntry) {
 1432        if !entry.selections.is_empty() {
 1433            match self.mode {
 1434                SelectionHistoryMode::Normal => {
 1435                    self.push_undo(entry);
 1436                    self.redo_stack.clear();
 1437                }
 1438                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1439                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1440                SelectionHistoryMode::Skipping => {}
 1441            }
 1442        }
 1443    }
 1444
 1445    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1446        if self
 1447            .undo_stack
 1448            .back()
 1449            .is_none_or(|e| e.selections != entry.selections)
 1450        {
 1451            self.undo_stack.push_back(entry);
 1452            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1453                self.undo_stack.pop_front();
 1454            }
 1455        }
 1456    }
 1457
 1458    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1459        if self
 1460            .redo_stack
 1461            .back()
 1462            .is_none_or(|e| e.selections != entry.selections)
 1463        {
 1464            self.redo_stack.push_back(entry);
 1465            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1466                self.redo_stack.pop_front();
 1467            }
 1468        }
 1469    }
 1470}
 1471
 1472#[derive(Clone, Copy)]
 1473pub struct RowHighlightOptions {
 1474    pub autoscroll: bool,
 1475    pub include_gutter: bool,
 1476}
 1477
 1478impl Default for RowHighlightOptions {
 1479    fn default() -> Self {
 1480        Self {
 1481            autoscroll: Default::default(),
 1482            include_gutter: true,
 1483        }
 1484    }
 1485}
 1486
 1487struct RowHighlight {
 1488    index: usize,
 1489    range: Range<Anchor>,
 1490    color: Hsla,
 1491    options: RowHighlightOptions,
 1492    type_id: TypeId,
 1493}
 1494
 1495#[derive(Clone, Debug)]
 1496struct AddSelectionsState {
 1497    groups: Vec<AddSelectionsGroup>,
 1498}
 1499
 1500#[derive(Clone, Debug)]
 1501struct AddSelectionsGroup {
 1502    above: bool,
 1503    stack: Vec<usize>,
 1504}
 1505
 1506#[derive(Clone)]
 1507struct SelectNextState {
 1508    query: AhoCorasick,
 1509    wordwise: bool,
 1510    done: bool,
 1511}
 1512
 1513impl std::fmt::Debug for SelectNextState {
 1514    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1515        f.debug_struct(std::any::type_name::<Self>())
 1516            .field("wordwise", &self.wordwise)
 1517            .field("done", &self.done)
 1518            .finish()
 1519    }
 1520}
 1521
 1522#[derive(Debug)]
 1523struct AutocloseRegion {
 1524    selection_id: usize,
 1525    range: Range<Anchor>,
 1526    pair: BracketPair,
 1527}
 1528
 1529#[derive(Debug)]
 1530struct SnippetState {
 1531    ranges: Vec<Vec<Range<Anchor>>>,
 1532    active_index: usize,
 1533    choices: Vec<Option<Vec<String>>>,
 1534}
 1535
 1536#[doc(hidden)]
 1537pub struct RenameState {
 1538    pub range: Range<Anchor>,
 1539    pub old_name: Arc<str>,
 1540    pub editor: Entity<Editor>,
 1541    block_id: CustomBlockId,
 1542}
 1543
 1544struct InvalidationStack<T>(Vec<T>);
 1545
 1546struct RegisteredEditPredictionProvider {
 1547    provider: Arc<dyn EditPredictionProviderHandle>,
 1548    _subscription: Subscription,
 1549}
 1550
 1551#[derive(Debug, PartialEq, Eq)]
 1552pub struct ActiveDiagnosticGroup {
 1553    pub active_range: Range<Anchor>,
 1554    pub active_message: String,
 1555    pub group_id: usize,
 1556    pub blocks: HashSet<CustomBlockId>,
 1557}
 1558
 1559#[derive(Debug, PartialEq, Eq)]
 1560
 1561pub(crate) enum ActiveDiagnostic {
 1562    None,
 1563    All,
 1564    Group(ActiveDiagnosticGroup),
 1565}
 1566
 1567#[derive(Serialize, Deserialize, Clone, Debug)]
 1568pub struct ClipboardSelection {
 1569    /// The number of bytes in this selection.
 1570    pub len: usize,
 1571    /// Whether this was a full-line selection.
 1572    pub is_entire_line: bool,
 1573    /// The indentation of the first line when this content was originally copied.
 1574    pub first_line_indent: u32,
 1575}
 1576
 1577// selections, scroll behavior, was newest selection reversed
 1578type SelectSyntaxNodeHistoryState = (
 1579    Box<[Selection<usize>]>,
 1580    SelectSyntaxNodeScrollBehavior,
 1581    bool,
 1582);
 1583
 1584#[derive(Default)]
 1585struct SelectSyntaxNodeHistory {
 1586    stack: Vec<SelectSyntaxNodeHistoryState>,
 1587    // disable temporarily to allow changing selections without losing the stack
 1588    pub disable_clearing: bool,
 1589}
 1590
 1591impl SelectSyntaxNodeHistory {
 1592    pub fn try_clear(&mut self) {
 1593        if !self.disable_clearing {
 1594            self.stack.clear();
 1595        }
 1596    }
 1597
 1598    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1599        self.stack.push(selection);
 1600    }
 1601
 1602    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1603        self.stack.pop()
 1604    }
 1605}
 1606
 1607enum SelectSyntaxNodeScrollBehavior {
 1608    CursorTop,
 1609    FitSelection,
 1610    CursorBottom,
 1611}
 1612
 1613#[derive(Debug)]
 1614pub(crate) struct NavigationData {
 1615    cursor_anchor: Anchor,
 1616    cursor_position: Point,
 1617    scroll_anchor: ScrollAnchor,
 1618    scroll_top_row: u32,
 1619}
 1620
 1621#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1622pub enum GotoDefinitionKind {
 1623    Symbol,
 1624    Declaration,
 1625    Type,
 1626    Implementation,
 1627}
 1628
 1629pub enum FormatTarget {
 1630    Buffers(HashSet<Entity<Buffer>>),
 1631    Ranges(Vec<Range<MultiBufferPoint>>),
 1632}
 1633
 1634pub(crate) struct FocusedBlock {
 1635    id: BlockId,
 1636    focus_handle: WeakFocusHandle,
 1637}
 1638
 1639#[derive(Clone)]
 1640enum JumpData {
 1641    MultiBufferRow {
 1642        row: MultiBufferRow,
 1643        line_offset_from_top: u32,
 1644    },
 1645    MultiBufferPoint {
 1646        excerpt_id: ExcerptId,
 1647        position: Point,
 1648        anchor: text::Anchor,
 1649        line_offset_from_top: u32,
 1650    },
 1651}
 1652
 1653pub enum MultibufferSelectionMode {
 1654    First,
 1655    All,
 1656}
 1657
 1658#[derive(Clone, Copy, Debug, Default)]
 1659pub struct RewrapOptions {
 1660    pub override_language_settings: bool,
 1661    pub preserve_existing_whitespace: bool,
 1662}
 1663
 1664impl Editor {
 1665    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1666        let buffer = cx.new(|cx| Buffer::local("", cx));
 1667        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1668        Self::new(EditorMode::SingleLine, buffer, None, window, cx)
 1669    }
 1670
 1671    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1672        let buffer = cx.new(|cx| Buffer::local("", cx));
 1673        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1674        Self::new(EditorMode::full(), buffer, None, window, cx)
 1675    }
 1676
 1677    pub fn auto_height(
 1678        min_lines: usize,
 1679        max_lines: usize,
 1680        window: &mut Window,
 1681        cx: &mut Context<Self>,
 1682    ) -> Self {
 1683        let buffer = cx.new(|cx| Buffer::local("", cx));
 1684        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1685        Self::new(
 1686            EditorMode::AutoHeight {
 1687                min_lines,
 1688                max_lines: Some(max_lines),
 1689            },
 1690            buffer,
 1691            None,
 1692            window,
 1693            cx,
 1694        )
 1695    }
 1696
 1697    /// Creates a new auto-height editor with a minimum number of lines but no maximum.
 1698    /// The editor grows as tall as needed to fit its content.
 1699    pub fn auto_height_unbounded(
 1700        min_lines: usize,
 1701        window: &mut Window,
 1702        cx: &mut Context<Self>,
 1703    ) -> Self {
 1704        let buffer = cx.new(|cx| Buffer::local("", cx));
 1705        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1706        Self::new(
 1707            EditorMode::AutoHeight {
 1708                min_lines,
 1709                max_lines: None,
 1710            },
 1711            buffer,
 1712            None,
 1713            window,
 1714            cx,
 1715        )
 1716    }
 1717
 1718    pub fn for_buffer(
 1719        buffer: Entity<Buffer>,
 1720        project: Option<Entity<Project>>,
 1721        window: &mut Window,
 1722        cx: &mut Context<Self>,
 1723    ) -> Self {
 1724        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1725        Self::new(EditorMode::full(), buffer, project, window, cx)
 1726    }
 1727
 1728    pub fn for_multibuffer(
 1729        buffer: Entity<MultiBuffer>,
 1730        project: Option<Entity<Project>>,
 1731        window: &mut Window,
 1732        cx: &mut Context<Self>,
 1733    ) -> Self {
 1734        Self::new(EditorMode::full(), buffer, project, window, cx)
 1735    }
 1736
 1737    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1738        let mut clone = Self::new(
 1739            self.mode.clone(),
 1740            self.buffer.clone(),
 1741            self.project.clone(),
 1742            window,
 1743            cx,
 1744        );
 1745        self.display_map.update(cx, |display_map, cx| {
 1746            let snapshot = display_map.snapshot(cx);
 1747            clone.display_map.update(cx, |display_map, cx| {
 1748                display_map.set_state(&snapshot, cx);
 1749            });
 1750        });
 1751        clone.folds_did_change(cx);
 1752        clone.selections.clone_state(&self.selections);
 1753        clone.scroll_manager.clone_state(&self.scroll_manager);
 1754        clone.searchable = self.searchable;
 1755        clone.read_only = self.read_only;
 1756        clone
 1757    }
 1758
 1759    pub fn new(
 1760        mode: EditorMode,
 1761        buffer: Entity<MultiBuffer>,
 1762        project: Option<Entity<Project>>,
 1763        window: &mut Window,
 1764        cx: &mut Context<Self>,
 1765    ) -> Self {
 1766        Editor::new_internal(mode, buffer, project, None, window, cx)
 1767    }
 1768
 1769    pub fn sticky_headers(&self, cx: &App) -> Option<Vec<OutlineItem<Anchor>>> {
 1770        let multi_buffer = self.buffer().read(cx);
 1771        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 1772        let multi_buffer_visible_start = self
 1773            .scroll_manager
 1774            .anchor()
 1775            .anchor
 1776            .to_point(&multi_buffer_snapshot);
 1777        let max_row = multi_buffer_snapshot.max_point().row;
 1778
 1779        let start_row = (multi_buffer_visible_start.row).min(max_row);
 1780        let end_row = (multi_buffer_visible_start.row + 10).min(max_row);
 1781
 1782        if let Some((excerpt_id, buffer_id, buffer)) = multi_buffer.read(cx).as_singleton() {
 1783            let outline_items = buffer
 1784                .outline_items_containing(
 1785                    Point::new(start_row, 0)..Point::new(end_row, 0),
 1786                    true,
 1787                    self.style().map(|style| style.syntax.as_ref()),
 1788                )
 1789                .into_iter()
 1790                .map(|outline_item| OutlineItem {
 1791                    depth: outline_item.depth,
 1792                    range: Anchor::range_in_buffer(*excerpt_id, buffer_id, outline_item.range),
 1793                    source_range_for_text: Anchor::range_in_buffer(
 1794                        *excerpt_id,
 1795                        buffer_id,
 1796                        outline_item.source_range_for_text,
 1797                    ),
 1798                    text: outline_item.text,
 1799                    highlight_ranges: outline_item.highlight_ranges,
 1800                    name_ranges: outline_item.name_ranges,
 1801                    body_range: outline_item
 1802                        .body_range
 1803                        .map(|range| Anchor::range_in_buffer(*excerpt_id, buffer_id, range)),
 1804                    annotation_range: outline_item
 1805                        .annotation_range
 1806                        .map(|range| Anchor::range_in_buffer(*excerpt_id, buffer_id, range)),
 1807                });
 1808            return Some(outline_items.collect());
 1809        }
 1810
 1811        None
 1812    }
 1813
 1814    fn new_internal(
 1815        mode: EditorMode,
 1816        multi_buffer: Entity<MultiBuffer>,
 1817        project: Option<Entity<Project>>,
 1818        display_map: Option<Entity<DisplayMap>>,
 1819        window: &mut Window,
 1820        cx: &mut Context<Self>,
 1821    ) -> Self {
 1822        debug_assert!(
 1823            display_map.is_none() || mode.is_minimap(),
 1824            "Providing a display map for a new editor is only intended for the minimap and might have unintended side effects otherwise!"
 1825        );
 1826
 1827        let full_mode = mode.is_full();
 1828        let is_minimap = mode.is_minimap();
 1829        let diagnostics_max_severity = if full_mode {
 1830            EditorSettings::get_global(cx)
 1831                .diagnostics_max_severity
 1832                .unwrap_or(DiagnosticSeverity::Hint)
 1833        } else {
 1834            DiagnosticSeverity::Off
 1835        };
 1836        let style = window.text_style();
 1837        let font_size = style.font_size.to_pixels(window.rem_size());
 1838        let editor = cx.entity().downgrade();
 1839        let fold_placeholder = FoldPlaceholder {
 1840            constrain_width: false,
 1841            render: Arc::new(move |fold_id, fold_range, cx| {
 1842                let editor = editor.clone();
 1843                div()
 1844                    .id(fold_id)
 1845                    .bg(cx.theme().colors().ghost_element_background)
 1846                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1847                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1848                    .rounded_xs()
 1849                    .size_full()
 1850                    .cursor_pointer()
 1851                    .child("")
 1852                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1853                    .on_click(move |_, _window, cx| {
 1854                        editor
 1855                            .update(cx, |editor, cx| {
 1856                                editor.unfold_ranges(
 1857                                    &[fold_range.start..fold_range.end],
 1858                                    true,
 1859                                    false,
 1860                                    cx,
 1861                                );
 1862                                cx.stop_propagation();
 1863                            })
 1864                            .ok();
 1865                    })
 1866                    .into_any()
 1867            }),
 1868            merge_adjacent: true,
 1869            ..FoldPlaceholder::default()
 1870        };
 1871        let display_map = display_map.unwrap_or_else(|| {
 1872            cx.new(|cx| {
 1873                DisplayMap::new(
 1874                    multi_buffer.clone(),
 1875                    style.font(),
 1876                    font_size,
 1877                    None,
 1878                    FILE_HEADER_HEIGHT,
 1879                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1880                    fold_placeholder,
 1881                    diagnostics_max_severity,
 1882                    cx,
 1883                )
 1884            })
 1885        });
 1886
 1887        let selections = SelectionsCollection::new();
 1888
 1889        let blink_manager = cx.new(|cx| {
 1890            let mut blink_manager = BlinkManager::new(CURSOR_BLINK_INTERVAL, cx);
 1891            if is_minimap {
 1892                blink_manager.disable(cx);
 1893            }
 1894            blink_manager
 1895        });
 1896
 1897        let soft_wrap_mode_override =
 1898            matches!(mode, EditorMode::SingleLine).then(|| language_settings::SoftWrap::None);
 1899
 1900        let mut project_subscriptions = Vec::new();
 1901        if full_mode && let Some(project) = project.as_ref() {
 1902            project_subscriptions.push(cx.subscribe_in(
 1903                project,
 1904                window,
 1905                |editor, _, event, window, cx| match event {
 1906                    project::Event::RefreshCodeLens => {
 1907                        // we always query lens with actions, without storing them, always refreshing them
 1908                    }
 1909                    project::Event::RefreshInlayHints {
 1910                        server_id,
 1911                        request_id,
 1912                    } => {
 1913                        editor.refresh_inlay_hints(
 1914                            InlayHintRefreshReason::RefreshRequested {
 1915                                server_id: *server_id,
 1916                                request_id: *request_id,
 1917                            },
 1918                            cx,
 1919                        );
 1920                    }
 1921                    project::Event::LanguageServerRemoved(..) => {
 1922                        if editor.tasks_update_task.is_none() {
 1923                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1924                        }
 1925                        editor.registered_buffers.clear();
 1926                        editor.register_visible_buffers(cx);
 1927                    }
 1928                    project::Event::LanguageServerAdded(..) => {
 1929                        if editor.tasks_update_task.is_none() {
 1930                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1931                        }
 1932                    }
 1933                    project::Event::SnippetEdit(id, snippet_edits) => {
 1934                        if let Some(buffer) = editor.buffer.read(cx).buffer(*id) {
 1935                            let focus_handle = editor.focus_handle(cx);
 1936                            if focus_handle.is_focused(window) {
 1937                                let snapshot = buffer.read(cx).snapshot();
 1938                                for (range, snippet) in snippet_edits {
 1939                                    let editor_range =
 1940                                        language::range_from_lsp(*range).to_offset(&snapshot);
 1941                                    editor
 1942                                        .insert_snippet(
 1943                                            &[editor_range],
 1944                                            snippet.clone(),
 1945                                            window,
 1946                                            cx,
 1947                                        )
 1948                                        .ok();
 1949                                }
 1950                            }
 1951                        }
 1952                    }
 1953                    project::Event::LanguageServerBufferRegistered { buffer_id, .. } => {
 1954                        let buffer_id = *buffer_id;
 1955                        if editor.buffer().read(cx).buffer(buffer_id).is_some() {
 1956                            editor.register_buffer(buffer_id, cx);
 1957                            editor.update_lsp_data(Some(buffer_id), window, cx);
 1958                            editor.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
 1959                            refresh_linked_ranges(editor, window, cx);
 1960                            editor.refresh_code_actions(window, cx);
 1961                            editor.refresh_document_highlights(cx);
 1962                        }
 1963                    }
 1964
 1965                    project::Event::EntryRenamed(transaction, project_path, abs_path) => {
 1966                        let Some(workspace) = editor.workspace() else {
 1967                            return;
 1968                        };
 1969                        let Some(active_editor) = workspace.read(cx).active_item_as::<Self>(cx)
 1970                        else {
 1971                            return;
 1972                        };
 1973
 1974                        if active_editor.entity_id() == cx.entity_id() {
 1975                            let entity_id = cx.entity_id();
 1976                            workspace.update(cx, |this, cx| {
 1977                                this.panes_mut()
 1978                                    .iter_mut()
 1979                                    .filter(|pane| pane.entity_id() != entity_id)
 1980                                    .for_each(|p| {
 1981                                        p.update(cx, |pane, _| {
 1982                                            pane.nav_history_mut().rename_item(
 1983                                                entity_id,
 1984                                                project_path.clone(),
 1985                                                abs_path.clone().into(),
 1986                                            );
 1987                                        })
 1988                                    });
 1989                            });
 1990                            let edited_buffers_already_open = {
 1991                                let other_editors: Vec<Entity<Editor>> = workspace
 1992                                    .read(cx)
 1993                                    .panes()
 1994                                    .iter()
 1995                                    .flat_map(|pane| pane.read(cx).items_of_type::<Editor>())
 1996                                    .filter(|editor| editor.entity_id() != cx.entity_id())
 1997                                    .collect();
 1998
 1999                                transaction.0.keys().all(|buffer| {
 2000                                    other_editors.iter().any(|editor| {
 2001                                        let multi_buffer = editor.read(cx).buffer();
 2002                                        multi_buffer.read(cx).is_singleton()
 2003                                            && multi_buffer.read(cx).as_singleton().map_or(
 2004                                                false,
 2005                                                |singleton| {
 2006                                                    singleton.entity_id() == buffer.entity_id()
 2007                                                },
 2008                                            )
 2009                                    })
 2010                                })
 2011                            };
 2012                            if !edited_buffers_already_open {
 2013                                let workspace = workspace.downgrade();
 2014                                let transaction = transaction.clone();
 2015                                cx.defer_in(window, move |_, window, cx| {
 2016                                    cx.spawn_in(window, async move |editor, cx| {
 2017                                        Self::open_project_transaction(
 2018                                            &editor,
 2019                                            workspace,
 2020                                            transaction,
 2021                                            "Rename".to_string(),
 2022                                            cx,
 2023                                        )
 2024                                        .await
 2025                                        .ok()
 2026                                    })
 2027                                    .detach();
 2028                                });
 2029                            }
 2030                        }
 2031                    }
 2032
 2033                    _ => {}
 2034                },
 2035            ));
 2036            if let Some(task_inventory) = project
 2037                .read(cx)
 2038                .task_store()
 2039                .read(cx)
 2040                .task_inventory()
 2041                .cloned()
 2042            {
 2043                project_subscriptions.push(cx.observe_in(
 2044                    &task_inventory,
 2045                    window,
 2046                    |editor, _, window, cx| {
 2047                        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2048                    },
 2049                ));
 2050            };
 2051
 2052            project_subscriptions.push(cx.subscribe_in(
 2053                &project.read(cx).breakpoint_store(),
 2054                window,
 2055                |editor, _, event, window, cx| match event {
 2056                    BreakpointStoreEvent::ClearDebugLines => {
 2057                        editor.clear_row_highlights::<ActiveDebugLine>();
 2058                        editor.refresh_inline_values(cx);
 2059                    }
 2060                    BreakpointStoreEvent::SetDebugLine => {
 2061                        if editor.go_to_active_debug_line(window, cx) {
 2062                            cx.stop_propagation();
 2063                        }
 2064
 2065                        editor.refresh_inline_values(cx);
 2066                    }
 2067                    _ => {}
 2068                },
 2069            ));
 2070            let git_store = project.read(cx).git_store().clone();
 2071            let project = project.clone();
 2072            project_subscriptions.push(cx.subscribe(&git_store, move |this, _, event, cx| {
 2073                if let GitStoreEvent::RepositoryAdded = event {
 2074                    this.load_diff_task = Some(
 2075                        update_uncommitted_diff_for_buffer(
 2076                            cx.entity(),
 2077                            &project,
 2078                            this.buffer.read(cx).all_buffers(),
 2079                            this.buffer.clone(),
 2080                            cx,
 2081                        )
 2082                        .shared(),
 2083                    );
 2084                }
 2085            }));
 2086        }
 2087
 2088        let buffer_snapshot = multi_buffer.read(cx).snapshot(cx);
 2089
 2090        let inlay_hint_settings =
 2091            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 2092        let focus_handle = cx.focus_handle();
 2093        if !is_minimap {
 2094            cx.on_focus(&focus_handle, window, Self::handle_focus)
 2095                .detach();
 2096            cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 2097                .detach();
 2098            cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 2099                .detach();
 2100            cx.on_blur(&focus_handle, window, Self::handle_blur)
 2101                .detach();
 2102            cx.observe_pending_input(window, Self::observe_pending_input)
 2103                .detach();
 2104        }
 2105
 2106        let show_indent_guides =
 2107            if matches!(mode, EditorMode::SingleLine | EditorMode::Minimap { .. }) {
 2108                Some(false)
 2109            } else {
 2110                None
 2111            };
 2112
 2113        let breakpoint_store = match (&mode, project.as_ref()) {
 2114            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 2115            _ => None,
 2116        };
 2117
 2118        let mut code_action_providers = Vec::new();
 2119        let mut load_uncommitted_diff = None;
 2120        if let Some(project) = project.clone() {
 2121            load_uncommitted_diff = Some(
 2122                update_uncommitted_diff_for_buffer(
 2123                    cx.entity(),
 2124                    &project,
 2125                    multi_buffer.read(cx).all_buffers(),
 2126                    multi_buffer.clone(),
 2127                    cx,
 2128                )
 2129                .shared(),
 2130            );
 2131            code_action_providers.push(Rc::new(project) as Rc<_>);
 2132        }
 2133
 2134        let mut editor = Self {
 2135            focus_handle,
 2136            show_cursor_when_unfocused: false,
 2137            last_focused_descendant: None,
 2138            buffer: multi_buffer.clone(),
 2139            display_map: display_map.clone(),
 2140            placeholder_display_map: None,
 2141            selections,
 2142            scroll_manager: ScrollManager::new(cx),
 2143            columnar_selection_state: None,
 2144            add_selections_state: None,
 2145            select_next_state: None,
 2146            select_prev_state: None,
 2147            selection_history: SelectionHistory::default(),
 2148            defer_selection_effects: false,
 2149            deferred_selection_effects_state: None,
 2150            autoclose_regions: Vec::new(),
 2151            snippet_stack: InvalidationStack::default(),
 2152            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 2153            ime_transaction: None,
 2154            active_diagnostics: ActiveDiagnostic::None,
 2155            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 2156            inline_diagnostics_update: Task::ready(()),
 2157            inline_diagnostics: Vec::new(),
 2158            soft_wrap_mode_override,
 2159            diagnostics_max_severity,
 2160            hard_wrap: None,
 2161            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 2162            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 2163            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 2164            project,
 2165            blink_manager: blink_manager.clone(),
 2166            show_local_selections: true,
 2167            show_scrollbars: ScrollbarAxes {
 2168                horizontal: full_mode,
 2169                vertical: full_mode,
 2170            },
 2171            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 2172            offset_content: !matches!(mode, EditorMode::SingleLine),
 2173            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 2174            show_gutter: full_mode,
 2175            show_line_numbers: (!full_mode).then_some(false),
 2176            use_relative_line_numbers: None,
 2177            disable_expand_excerpt_buttons: !full_mode,
 2178            show_git_diff_gutter: None,
 2179            show_code_actions: None,
 2180            show_runnables: None,
 2181            show_breakpoints: None,
 2182            show_wrap_guides: None,
 2183            show_indent_guides,
 2184            highlight_order: 0,
 2185            highlighted_rows: HashMap::default(),
 2186            background_highlights: HashMap::default(),
 2187            gutter_highlights: HashMap::default(),
 2188            scrollbar_marker_state: ScrollbarMarkerState::default(),
 2189            active_indent_guides_state: ActiveIndentGuidesState::default(),
 2190            nav_history: None,
 2191            context_menu: RefCell::new(None),
 2192            context_menu_options: None,
 2193            mouse_context_menu: None,
 2194            completion_tasks: Vec::new(),
 2195            inline_blame_popover: None,
 2196            inline_blame_popover_show_task: None,
 2197            signature_help_state: SignatureHelpState::default(),
 2198            auto_signature_help: None,
 2199            find_all_references_task_sources: Vec::new(),
 2200            next_completion_id: 0,
 2201            next_inlay_id: 0,
 2202            code_action_providers,
 2203            available_code_actions: None,
 2204            code_actions_task: None,
 2205            quick_selection_highlight_task: None,
 2206            debounced_selection_highlight_task: None,
 2207            document_highlights_task: None,
 2208            linked_editing_range_task: None,
 2209            pending_rename: None,
 2210            searchable: !is_minimap,
 2211            cursor_shape: EditorSettings::get_global(cx)
 2212                .cursor_shape
 2213                .unwrap_or_default(),
 2214            current_line_highlight: None,
 2215            autoindent_mode: Some(AutoindentMode::EachLine),
 2216
 2217            workspace: None,
 2218            input_enabled: !is_minimap,
 2219            use_modal_editing: full_mode,
 2220            read_only: is_minimap,
 2221            use_autoclose: true,
 2222            use_auto_surround: true,
 2223            auto_replace_emoji_shortcode: false,
 2224            jsx_tag_auto_close_enabled_in_any_buffer: false,
 2225            leader_id: None,
 2226            remote_id: None,
 2227            hover_state: HoverState::default(),
 2228            pending_mouse_down: None,
 2229            hovered_link_state: None,
 2230            edit_prediction_provider: None,
 2231            active_edit_prediction: None,
 2232            stale_edit_prediction_in_menu: None,
 2233            edit_prediction_preview: EditPredictionPreview::Inactive {
 2234                released_too_fast: false,
 2235            },
 2236            inline_diagnostics_enabled: full_mode,
 2237            diagnostics_enabled: full_mode,
 2238            word_completions_enabled: full_mode,
 2239            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 2240            gutter_hovered: false,
 2241            pixel_position_of_newest_cursor: None,
 2242            last_bounds: None,
 2243            last_position_map: None,
 2244            expect_bounds_change: None,
 2245            gutter_dimensions: GutterDimensions::default(),
 2246            style: None,
 2247            show_cursor_names: false,
 2248            hovered_cursors: HashMap::default(),
 2249            next_editor_action_id: EditorActionId::default(),
 2250            editor_actions: Rc::default(),
 2251            edit_predictions_hidden_for_vim_mode: false,
 2252            show_edit_predictions_override: None,
 2253            menu_edit_predictions_policy: MenuEditPredictionsPolicy::ByProvider,
 2254            edit_prediction_settings: EditPredictionSettings::Disabled,
 2255            edit_prediction_indent_conflict: false,
 2256            edit_prediction_requires_modifier_in_indent_conflict: true,
 2257            custom_context_menu: None,
 2258            show_git_blame_gutter: false,
 2259            show_git_blame_inline: false,
 2260            show_selection_menu: None,
 2261            show_git_blame_inline_delay_task: None,
 2262            git_blame_inline_enabled: full_mode
 2263                && ProjectSettings::get_global(cx).git.inline_blame.enabled,
 2264            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 2265            buffer_serialization: is_minimap.not().then(|| {
 2266                BufferSerialization::new(
 2267                    ProjectSettings::get_global(cx)
 2268                        .session
 2269                        .restore_unsaved_buffers,
 2270                )
 2271            }),
 2272            blame: None,
 2273            blame_subscription: None,
 2274            tasks: BTreeMap::default(),
 2275
 2276            breakpoint_store,
 2277            gutter_breakpoint_indicator: (None, None),
 2278            hovered_diff_hunk_row: None,
 2279            _subscriptions: (!is_minimap)
 2280                .then(|| {
 2281                    vec![
 2282                        cx.observe(&multi_buffer, Self::on_buffer_changed),
 2283                        cx.subscribe_in(&multi_buffer, window, Self::on_buffer_event),
 2284                        cx.observe_in(&display_map, window, Self::on_display_map_changed),
 2285                        cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 2286                        cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 2287                        observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 2288                        cx.observe_window_activation(window, |editor, window, cx| {
 2289                            let active = window.is_window_active();
 2290                            editor.blink_manager.update(cx, |blink_manager, cx| {
 2291                                if active {
 2292                                    blink_manager.enable(cx);
 2293                                } else {
 2294                                    blink_manager.disable(cx);
 2295                                }
 2296                            });
 2297                            if active {
 2298                                editor.show_mouse_cursor(cx);
 2299                            }
 2300                        }),
 2301                    ]
 2302                })
 2303                .unwrap_or_default(),
 2304            tasks_update_task: None,
 2305            pull_diagnostics_task: Task::ready(()),
 2306            colors: None,
 2307            refresh_colors_task: Task::ready(()),
 2308            inlay_hints: None,
 2309            next_color_inlay_id: 0,
 2310            post_scroll_update: Task::ready(()),
 2311            linked_edit_ranges: Default::default(),
 2312            in_project_search: false,
 2313            previous_search_ranges: None,
 2314            breadcrumb_header: None,
 2315            focused_block: None,
 2316            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 2317            addons: HashMap::default(),
 2318            registered_buffers: HashMap::default(),
 2319            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 2320            selection_mark_mode: false,
 2321            toggle_fold_multiple_buffers: Task::ready(()),
 2322            serialize_selections: Task::ready(()),
 2323            serialize_folds: Task::ready(()),
 2324            text_style_refinement: None,
 2325            load_diff_task: load_uncommitted_diff,
 2326            temporary_diff_override: false,
 2327            mouse_cursor_hidden: false,
 2328            minimap: None,
 2329            hide_mouse_mode: EditorSettings::get_global(cx)
 2330                .hide_mouse
 2331                .unwrap_or_default(),
 2332            change_list: ChangeList::new(),
 2333            mode,
 2334            selection_drag_state: SelectionDragState::None,
 2335            folding_newlines: Task::ready(()),
 2336            lookup_key: None,
 2337            select_next_is_case_sensitive: None,
 2338        };
 2339
 2340        if is_minimap {
 2341            return editor;
 2342        }
 2343
 2344        if let Some(breakpoints) = editor.breakpoint_store.as_ref() {
 2345            editor
 2346                ._subscriptions
 2347                .push(cx.observe(breakpoints, |_, _, cx| {
 2348                    cx.notify();
 2349                }));
 2350        }
 2351        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2352        editor._subscriptions.extend(project_subscriptions);
 2353
 2354        editor._subscriptions.push(cx.subscribe_in(
 2355            &cx.entity(),
 2356            window,
 2357            |editor, _, e: &EditorEvent, window, cx| match e {
 2358                EditorEvent::ScrollPositionChanged { local, .. } => {
 2359                    if *local {
 2360                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 2361                        editor.inline_blame_popover.take();
 2362                        let new_anchor = editor.scroll_manager.anchor();
 2363                        let snapshot = editor.snapshot(window, cx);
 2364                        editor.update_restoration_data(cx, move |data| {
 2365                            data.scroll_position = (
 2366                                new_anchor.top_row(snapshot.buffer_snapshot()),
 2367                                new_anchor.offset,
 2368                            );
 2369                        });
 2370
 2371                        editor.post_scroll_update = cx.spawn_in(window, async move |editor, cx| {
 2372                            cx.background_executor()
 2373                                .timer(Duration::from_millis(50))
 2374                                .await;
 2375                            editor
 2376                                .update_in(cx, |editor, window, cx| {
 2377                                    editor.register_visible_buffers(cx);
 2378                                    editor.refresh_colors_for_visible_range(None, window, cx);
 2379                                    editor.refresh_inlay_hints(
 2380                                        InlayHintRefreshReason::NewLinesShown,
 2381                                        cx,
 2382                                    );
 2383                                })
 2384                                .ok();
 2385                        });
 2386                    }
 2387                }
 2388                EditorEvent::Edited { .. } => {
 2389                    if vim_flavor(cx).is_none() {
 2390                        let display_map = editor.display_snapshot(cx);
 2391                        let selections = editor.selections.all_adjusted_display(&display_map);
 2392                        let pop_state = editor
 2393                            .change_list
 2394                            .last()
 2395                            .map(|previous| {
 2396                                previous.len() == selections.len()
 2397                                    && previous.iter().enumerate().all(|(ix, p)| {
 2398                                        p.to_display_point(&display_map).row()
 2399                                            == selections[ix].head().row()
 2400                                    })
 2401                            })
 2402                            .unwrap_or(false);
 2403                        let new_positions = selections
 2404                            .into_iter()
 2405                            .map(|s| display_map.display_point_to_anchor(s.head(), Bias::Left))
 2406                            .collect();
 2407                        editor
 2408                            .change_list
 2409                            .push_to_change_list(pop_state, new_positions);
 2410                    }
 2411                }
 2412                _ => (),
 2413            },
 2414        ));
 2415
 2416        if let Some(dap_store) = editor
 2417            .project
 2418            .as_ref()
 2419            .map(|project| project.read(cx).dap_store())
 2420        {
 2421            let weak_editor = cx.weak_entity();
 2422
 2423            editor
 2424                ._subscriptions
 2425                .push(
 2426                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2427                        let session_entity = cx.entity();
 2428                        weak_editor
 2429                            .update(cx, |editor, cx| {
 2430                                editor._subscriptions.push(
 2431                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2432                                );
 2433                            })
 2434                            .ok();
 2435                    }),
 2436                );
 2437
 2438            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2439                editor
 2440                    ._subscriptions
 2441                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2442            }
 2443        }
 2444
 2445        // skip adding the initial selection to selection history
 2446        editor.selection_history.mode = SelectionHistoryMode::Skipping;
 2447        editor.end_selection(window, cx);
 2448        editor.selection_history.mode = SelectionHistoryMode::Normal;
 2449
 2450        editor.scroll_manager.show_scrollbars(window, cx);
 2451        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut editor, &multi_buffer, cx);
 2452
 2453        if full_mode {
 2454            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2455            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2456
 2457            if editor.git_blame_inline_enabled {
 2458                editor.start_git_blame_inline(false, window, cx);
 2459            }
 2460
 2461            editor.go_to_active_debug_line(window, cx);
 2462
 2463            editor.minimap =
 2464                editor.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2465            editor.colors = Some(LspColorData::new(cx));
 2466            editor.inlay_hints = Some(LspInlayHintData::new(inlay_hint_settings));
 2467
 2468            if let Some(buffer) = multi_buffer.read(cx).as_singleton() {
 2469                editor.register_buffer(buffer.read(cx).remote_id(), cx);
 2470            }
 2471            editor.update_lsp_data(None, window, cx);
 2472            editor.report_editor_event(ReportEditorEvent::EditorOpened, None, cx);
 2473        }
 2474
 2475        editor
 2476    }
 2477
 2478    pub fn display_snapshot(&self, cx: &mut App) -> DisplaySnapshot {
 2479        self.display_map.update(cx, |map, cx| map.snapshot(cx))
 2480    }
 2481
 2482    pub fn deploy_mouse_context_menu(
 2483        &mut self,
 2484        position: gpui::Point<Pixels>,
 2485        context_menu: Entity<ContextMenu>,
 2486        window: &mut Window,
 2487        cx: &mut Context<Self>,
 2488    ) {
 2489        self.mouse_context_menu = Some(MouseContextMenu::new(
 2490            self,
 2491            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2492            context_menu,
 2493            window,
 2494            cx,
 2495        ));
 2496    }
 2497
 2498    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2499        self.mouse_context_menu
 2500            .as_ref()
 2501            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2502    }
 2503
 2504    pub fn is_range_selected(&mut self, range: &Range<Anchor>, cx: &mut Context<Self>) -> bool {
 2505        if self
 2506            .selections
 2507            .pending_anchor()
 2508            .is_some_and(|pending_selection| {
 2509                let snapshot = self.buffer().read(cx).snapshot(cx);
 2510                pending_selection.range().includes(range, &snapshot)
 2511            })
 2512        {
 2513            return true;
 2514        }
 2515
 2516        self.selections
 2517            .disjoint_in_range::<usize>(range.clone(), &self.display_snapshot(cx))
 2518            .into_iter()
 2519            .any(|selection| {
 2520                // This is needed to cover a corner case, if we just check for an existing
 2521                // selection in the fold range, having a cursor at the start of the fold
 2522                // marks it as selected. Non-empty selections don't cause this.
 2523                let length = selection.end - selection.start;
 2524                length > 0
 2525            })
 2526    }
 2527
 2528    pub fn key_context(&self, window: &mut Window, cx: &mut App) -> KeyContext {
 2529        self.key_context_internal(self.has_active_edit_prediction(), window, cx)
 2530    }
 2531
 2532    fn key_context_internal(
 2533        &self,
 2534        has_active_edit_prediction: bool,
 2535        window: &mut Window,
 2536        cx: &mut App,
 2537    ) -> KeyContext {
 2538        let mut key_context = KeyContext::new_with_defaults();
 2539        key_context.add("Editor");
 2540        let mode = match self.mode {
 2541            EditorMode::SingleLine => "single_line",
 2542            EditorMode::AutoHeight { .. } => "auto_height",
 2543            EditorMode::Minimap { .. } => "minimap",
 2544            EditorMode::Full { .. } => "full",
 2545        };
 2546
 2547        if EditorSettings::jupyter_enabled(cx) {
 2548            key_context.add("jupyter");
 2549        }
 2550
 2551        key_context.set("mode", mode);
 2552        if self.pending_rename.is_some() {
 2553            key_context.add("renaming");
 2554        }
 2555
 2556        if let Some(snippet_stack) = self.snippet_stack.last() {
 2557            key_context.add("in_snippet");
 2558
 2559            if snippet_stack.active_index > 0 {
 2560                key_context.add("has_previous_tabstop");
 2561            }
 2562
 2563            if snippet_stack.active_index < snippet_stack.ranges.len().saturating_sub(1) {
 2564                key_context.add("has_next_tabstop");
 2565            }
 2566        }
 2567
 2568        match self.context_menu.borrow().as_ref() {
 2569            Some(CodeContextMenu::Completions(menu)) => {
 2570                if menu.visible() {
 2571                    key_context.add("menu");
 2572                    key_context.add("showing_completions");
 2573                }
 2574            }
 2575            Some(CodeContextMenu::CodeActions(menu)) => {
 2576                if menu.visible() {
 2577                    key_context.add("menu");
 2578                    key_context.add("showing_code_actions")
 2579                }
 2580            }
 2581            None => {}
 2582        }
 2583
 2584        if self.signature_help_state.has_multiple_signatures() {
 2585            key_context.add("showing_signature_help");
 2586        }
 2587
 2588        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2589        if !self.focus_handle(cx).contains_focused(window, cx)
 2590            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2591        {
 2592            for addon in self.addons.values() {
 2593                addon.extend_key_context(&mut key_context, cx)
 2594            }
 2595        }
 2596
 2597        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2598            if let Some(extension) = singleton_buffer.read(cx).file().and_then(|file| {
 2599                Some(
 2600                    file.full_path(cx)
 2601                        .extension()?
 2602                        .to_string_lossy()
 2603                        .into_owned(),
 2604                )
 2605            }) {
 2606                key_context.set("extension", extension);
 2607            }
 2608        } else {
 2609            key_context.add("multibuffer");
 2610        }
 2611
 2612        if has_active_edit_prediction {
 2613            if self.edit_prediction_in_conflict() {
 2614                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2615            } else {
 2616                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2617                key_context.add("copilot_suggestion");
 2618            }
 2619        }
 2620
 2621        if self.selection_mark_mode {
 2622            key_context.add("selection_mode");
 2623        }
 2624
 2625        let disjoint = self.selections.disjoint_anchors();
 2626        let snapshot = self.snapshot(window, cx);
 2627        let snapshot = snapshot.buffer_snapshot();
 2628        if self.mode == EditorMode::SingleLine
 2629            && let [selection] = disjoint
 2630            && selection.start == selection.end
 2631            && selection.end.to_offset(snapshot) == snapshot.len()
 2632        {
 2633            key_context.add("end_of_input");
 2634        }
 2635
 2636        key_context
 2637    }
 2638
 2639    pub fn last_bounds(&self) -> Option<&Bounds<Pixels>> {
 2640        self.last_bounds.as_ref()
 2641    }
 2642
 2643    fn show_mouse_cursor(&mut self, cx: &mut Context<Self>) {
 2644        if self.mouse_cursor_hidden {
 2645            self.mouse_cursor_hidden = false;
 2646            cx.notify();
 2647        }
 2648    }
 2649
 2650    pub fn hide_mouse_cursor(&mut self, origin: HideMouseCursorOrigin, cx: &mut Context<Self>) {
 2651        let hide_mouse_cursor = match origin {
 2652            HideMouseCursorOrigin::TypingAction => {
 2653                matches!(
 2654                    self.hide_mouse_mode,
 2655                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2656                )
 2657            }
 2658            HideMouseCursorOrigin::MovementAction => {
 2659                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2660            }
 2661        };
 2662        if self.mouse_cursor_hidden != hide_mouse_cursor {
 2663            self.mouse_cursor_hidden = hide_mouse_cursor;
 2664            cx.notify();
 2665        }
 2666    }
 2667
 2668    pub fn edit_prediction_in_conflict(&self) -> bool {
 2669        if !self.show_edit_predictions_in_menu() {
 2670            return false;
 2671        }
 2672
 2673        let showing_completions = self
 2674            .context_menu
 2675            .borrow()
 2676            .as_ref()
 2677            .is_some_and(|context| matches!(context, CodeContextMenu::Completions(_)));
 2678
 2679        showing_completions
 2680            || self.edit_prediction_requires_modifier()
 2681            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2682            // bindings to insert tab characters.
 2683            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2684    }
 2685
 2686    pub fn accept_edit_prediction_keybind(
 2687        &self,
 2688        accept_partial: bool,
 2689        window: &mut Window,
 2690        cx: &mut App,
 2691    ) -> AcceptEditPredictionBinding {
 2692        let key_context = self.key_context_internal(true, window, cx);
 2693        let in_conflict = self.edit_prediction_in_conflict();
 2694
 2695        let bindings = if accept_partial {
 2696            window.bindings_for_action_in_context(&AcceptPartialEditPrediction, key_context)
 2697        } else {
 2698            window.bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2699        };
 2700
 2701        // TODO: if the binding contains multiple keystrokes, display all of them, not
 2702        // just the first one.
 2703        AcceptEditPredictionBinding(bindings.into_iter().rev().find(|binding| {
 2704            !in_conflict
 2705                || binding
 2706                    .keystrokes()
 2707                    .first()
 2708                    .is_some_and(|keystroke| keystroke.modifiers().modified())
 2709        }))
 2710    }
 2711
 2712    pub fn new_file(
 2713        workspace: &mut Workspace,
 2714        _: &workspace::NewFile,
 2715        window: &mut Window,
 2716        cx: &mut Context<Workspace>,
 2717    ) {
 2718        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2719            "Failed to create buffer",
 2720            window,
 2721            cx,
 2722            |e, _, _| match e.error_code() {
 2723                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2724                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2725                e.error_tag("required").unwrap_or("the latest version")
 2726            )),
 2727                _ => None,
 2728            },
 2729        );
 2730    }
 2731
 2732    pub fn new_in_workspace(
 2733        workspace: &mut Workspace,
 2734        window: &mut Window,
 2735        cx: &mut Context<Workspace>,
 2736    ) -> Task<Result<Entity<Editor>>> {
 2737        let project = workspace.project().clone();
 2738        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2739
 2740        cx.spawn_in(window, async move |workspace, cx| {
 2741            let buffer = create.await?;
 2742            workspace.update_in(cx, |workspace, window, cx| {
 2743                let editor =
 2744                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2745                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2746                editor
 2747            })
 2748        })
 2749    }
 2750
 2751    fn new_file_vertical(
 2752        workspace: &mut Workspace,
 2753        _: &workspace::NewFileSplitVertical,
 2754        window: &mut Window,
 2755        cx: &mut Context<Workspace>,
 2756    ) {
 2757        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2758    }
 2759
 2760    fn new_file_horizontal(
 2761        workspace: &mut Workspace,
 2762        _: &workspace::NewFileSplitHorizontal,
 2763        window: &mut Window,
 2764        cx: &mut Context<Workspace>,
 2765    ) {
 2766        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2767    }
 2768
 2769    fn new_file_split(
 2770        workspace: &mut Workspace,
 2771        action: &workspace::NewFileSplit,
 2772        window: &mut Window,
 2773        cx: &mut Context<Workspace>,
 2774    ) {
 2775        Self::new_file_in_direction(workspace, action.0, window, cx)
 2776    }
 2777
 2778    fn new_file_in_direction(
 2779        workspace: &mut Workspace,
 2780        direction: SplitDirection,
 2781        window: &mut Window,
 2782        cx: &mut Context<Workspace>,
 2783    ) {
 2784        let project = workspace.project().clone();
 2785        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2786
 2787        cx.spawn_in(window, async move |workspace, cx| {
 2788            let buffer = create.await?;
 2789            workspace.update_in(cx, move |workspace, window, cx| {
 2790                workspace.split_item(
 2791                    direction,
 2792                    Box::new(
 2793                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2794                    ),
 2795                    window,
 2796                    cx,
 2797                )
 2798            })?;
 2799            anyhow::Ok(())
 2800        })
 2801        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2802            match e.error_code() {
 2803                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2804                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2805                e.error_tag("required").unwrap_or("the latest version")
 2806            )),
 2807                _ => None,
 2808            }
 2809        });
 2810    }
 2811
 2812    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2813        self.leader_id
 2814    }
 2815
 2816    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2817        &self.buffer
 2818    }
 2819
 2820    pub fn project(&self) -> Option<&Entity<Project>> {
 2821        self.project.as_ref()
 2822    }
 2823
 2824    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2825        self.workspace.as_ref()?.0.upgrade()
 2826    }
 2827
 2828    /// Returns the workspace serialization ID if this editor should be serialized.
 2829    fn workspace_serialization_id(&self, _cx: &App) -> Option<WorkspaceId> {
 2830        self.workspace
 2831            .as_ref()
 2832            .filter(|_| self.should_serialize_buffer())
 2833            .and_then(|workspace| workspace.1)
 2834    }
 2835
 2836    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2837        self.buffer().read(cx).title(cx)
 2838    }
 2839
 2840    pub fn snapshot(&self, window: &Window, cx: &mut App) -> EditorSnapshot {
 2841        let git_blame_gutter_max_author_length = self
 2842            .render_git_blame_gutter(cx)
 2843            .then(|| {
 2844                if let Some(blame) = self.blame.as_ref() {
 2845                    let max_author_length =
 2846                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2847                    Some(max_author_length)
 2848                } else {
 2849                    None
 2850                }
 2851            })
 2852            .flatten();
 2853
 2854        EditorSnapshot {
 2855            mode: self.mode.clone(),
 2856            show_gutter: self.show_gutter,
 2857            show_line_numbers: self.show_line_numbers,
 2858            show_git_diff_gutter: self.show_git_diff_gutter,
 2859            show_code_actions: self.show_code_actions,
 2860            show_runnables: self.show_runnables,
 2861            show_breakpoints: self.show_breakpoints,
 2862            git_blame_gutter_max_author_length,
 2863            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2864            placeholder_display_snapshot: self
 2865                .placeholder_display_map
 2866                .as_ref()
 2867                .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx))),
 2868            scroll_anchor: self.scroll_manager.anchor(),
 2869            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2870            is_focused: self.focus_handle.is_focused(window),
 2871            current_line_highlight: self
 2872                .current_line_highlight
 2873                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2874            gutter_hovered: self.gutter_hovered,
 2875        }
 2876    }
 2877
 2878    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2879        self.buffer.read(cx).language_at(point, cx)
 2880    }
 2881
 2882    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2883        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2884    }
 2885
 2886    pub fn active_excerpt(
 2887        &self,
 2888        cx: &App,
 2889    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2890        self.buffer
 2891            .read(cx)
 2892            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2893    }
 2894
 2895    pub fn mode(&self) -> &EditorMode {
 2896        &self.mode
 2897    }
 2898
 2899    pub fn set_mode(&mut self, mode: EditorMode) {
 2900        self.mode = mode;
 2901    }
 2902
 2903    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2904        self.collaboration_hub.as_deref()
 2905    }
 2906
 2907    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2908        self.collaboration_hub = Some(hub);
 2909    }
 2910
 2911    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2912        self.in_project_search = in_project_search;
 2913    }
 2914
 2915    pub fn set_custom_context_menu(
 2916        &mut self,
 2917        f: impl 'static
 2918        + Fn(
 2919            &mut Self,
 2920            DisplayPoint,
 2921            &mut Window,
 2922            &mut Context<Self>,
 2923        ) -> Option<Entity<ui::ContextMenu>>,
 2924    ) {
 2925        self.custom_context_menu = Some(Box::new(f))
 2926    }
 2927
 2928    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 2929        self.completion_provider = provider;
 2930    }
 2931
 2932    #[cfg(any(test, feature = "test-support"))]
 2933    pub fn completion_provider(&self) -> Option<Rc<dyn CompletionProvider>> {
 2934        self.completion_provider.clone()
 2935    }
 2936
 2937    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 2938        self.semantics_provider.clone()
 2939    }
 2940
 2941    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 2942        self.semantics_provider = provider;
 2943    }
 2944
 2945    pub fn set_edit_prediction_provider<T>(
 2946        &mut self,
 2947        provider: Option<Entity<T>>,
 2948        window: &mut Window,
 2949        cx: &mut Context<Self>,
 2950    ) where
 2951        T: EditPredictionProvider,
 2952    {
 2953        self.edit_prediction_provider = provider.map(|provider| RegisteredEditPredictionProvider {
 2954            _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 2955                if this.focus_handle.is_focused(window) {
 2956                    this.update_visible_edit_prediction(window, cx);
 2957                }
 2958            }),
 2959            provider: Arc::new(provider),
 2960        });
 2961        self.update_edit_prediction_settings(cx);
 2962        self.refresh_edit_prediction(false, false, window, cx);
 2963    }
 2964
 2965    pub fn placeholder_text(&self, cx: &mut App) -> Option<String> {
 2966        self.placeholder_display_map
 2967            .as_ref()
 2968            .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx)).text())
 2969    }
 2970
 2971    pub fn set_placeholder_text(
 2972        &mut self,
 2973        placeholder_text: &str,
 2974        window: &mut Window,
 2975        cx: &mut Context<Self>,
 2976    ) {
 2977        let multibuffer = cx
 2978            .new(|cx| MultiBuffer::singleton(cx.new(|cx| Buffer::local(placeholder_text, cx)), cx));
 2979
 2980        let style = window.text_style();
 2981
 2982        self.placeholder_display_map = Some(cx.new(|cx| {
 2983            DisplayMap::new(
 2984                multibuffer,
 2985                style.font(),
 2986                style.font_size.to_pixels(window.rem_size()),
 2987                None,
 2988                FILE_HEADER_HEIGHT,
 2989                MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 2990                Default::default(),
 2991                DiagnosticSeverity::Off,
 2992                cx,
 2993            )
 2994        }));
 2995        cx.notify();
 2996    }
 2997
 2998    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 2999        self.cursor_shape = cursor_shape;
 3000
 3001        // Disrupt blink for immediate user feedback that the cursor shape has changed
 3002        self.blink_manager.update(cx, BlinkManager::show_cursor);
 3003
 3004        cx.notify();
 3005    }
 3006
 3007    pub fn set_current_line_highlight(
 3008        &mut self,
 3009        current_line_highlight: Option<CurrentLineHighlight>,
 3010    ) {
 3011        self.current_line_highlight = current_line_highlight;
 3012    }
 3013
 3014    pub fn range_for_match<T: std::marker::Copy>(
 3015        &self,
 3016        range: &Range<T>,
 3017        collapse: bool,
 3018    ) -> Range<T> {
 3019        if collapse {
 3020            return range.start..range.start;
 3021        }
 3022        range.clone()
 3023    }
 3024
 3025    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 3026        if self.display_map.read(cx).clip_at_line_ends != clip {
 3027            self.display_map
 3028                .update(cx, |map, _| map.clip_at_line_ends = clip);
 3029        }
 3030    }
 3031
 3032    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 3033        self.input_enabled = input_enabled;
 3034    }
 3035
 3036    pub fn set_edit_predictions_hidden_for_vim_mode(
 3037        &mut self,
 3038        hidden: bool,
 3039        window: &mut Window,
 3040        cx: &mut Context<Self>,
 3041    ) {
 3042        if hidden != self.edit_predictions_hidden_for_vim_mode {
 3043            self.edit_predictions_hidden_for_vim_mode = hidden;
 3044            if hidden {
 3045                self.update_visible_edit_prediction(window, cx);
 3046            } else {
 3047                self.refresh_edit_prediction(true, false, window, cx);
 3048            }
 3049        }
 3050    }
 3051
 3052    pub fn set_menu_edit_predictions_policy(&mut self, value: MenuEditPredictionsPolicy) {
 3053        self.menu_edit_predictions_policy = value;
 3054    }
 3055
 3056    pub fn set_autoindent(&mut self, autoindent: bool) {
 3057        if autoindent {
 3058            self.autoindent_mode = Some(AutoindentMode::EachLine);
 3059        } else {
 3060            self.autoindent_mode = None;
 3061        }
 3062    }
 3063
 3064    pub fn read_only(&self, cx: &App) -> bool {
 3065        self.read_only || self.buffer.read(cx).read_only()
 3066    }
 3067
 3068    pub fn set_read_only(&mut self, read_only: bool) {
 3069        self.read_only = read_only;
 3070    }
 3071
 3072    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 3073        self.use_autoclose = autoclose;
 3074    }
 3075
 3076    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 3077        self.use_auto_surround = auto_surround;
 3078    }
 3079
 3080    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 3081        self.auto_replace_emoji_shortcode = auto_replace;
 3082    }
 3083
 3084    pub fn set_should_serialize(&mut self, should_serialize: bool, cx: &App) {
 3085        self.buffer_serialization = should_serialize.then(|| {
 3086            BufferSerialization::new(
 3087                ProjectSettings::get_global(cx)
 3088                    .session
 3089                    .restore_unsaved_buffers,
 3090            )
 3091        })
 3092    }
 3093
 3094    fn should_serialize_buffer(&self) -> bool {
 3095        self.buffer_serialization.is_some()
 3096    }
 3097
 3098    pub fn toggle_edit_predictions(
 3099        &mut self,
 3100        _: &ToggleEditPrediction,
 3101        window: &mut Window,
 3102        cx: &mut Context<Self>,
 3103    ) {
 3104        if self.show_edit_predictions_override.is_some() {
 3105            self.set_show_edit_predictions(None, window, cx);
 3106        } else {
 3107            let show_edit_predictions = !self.edit_predictions_enabled();
 3108            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 3109        }
 3110    }
 3111
 3112    pub fn set_show_edit_predictions(
 3113        &mut self,
 3114        show_edit_predictions: Option<bool>,
 3115        window: &mut Window,
 3116        cx: &mut Context<Self>,
 3117    ) {
 3118        self.show_edit_predictions_override = show_edit_predictions;
 3119        self.update_edit_prediction_settings(cx);
 3120
 3121        if let Some(false) = show_edit_predictions {
 3122            self.discard_edit_prediction(false, cx);
 3123        } else {
 3124            self.refresh_edit_prediction(false, true, window, cx);
 3125        }
 3126    }
 3127
 3128    fn edit_predictions_disabled_in_scope(
 3129        &self,
 3130        buffer: &Entity<Buffer>,
 3131        buffer_position: language::Anchor,
 3132        cx: &App,
 3133    ) -> bool {
 3134        let snapshot = buffer.read(cx).snapshot();
 3135        let settings = snapshot.settings_at(buffer_position, cx);
 3136
 3137        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 3138            return false;
 3139        };
 3140
 3141        scope.override_name().is_some_and(|scope_name| {
 3142            settings
 3143                .edit_predictions_disabled_in
 3144                .iter()
 3145                .any(|s| s == scope_name)
 3146        })
 3147    }
 3148
 3149    pub fn set_use_modal_editing(&mut self, to: bool) {
 3150        self.use_modal_editing = to;
 3151    }
 3152
 3153    pub fn use_modal_editing(&self) -> bool {
 3154        self.use_modal_editing
 3155    }
 3156
 3157    fn selections_did_change(
 3158        &mut self,
 3159        local: bool,
 3160        old_cursor_position: &Anchor,
 3161        effects: SelectionEffects,
 3162        window: &mut Window,
 3163        cx: &mut Context<Self>,
 3164    ) {
 3165        window.invalidate_character_coordinates();
 3166
 3167        // Copy selections to primary selection buffer
 3168        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 3169        if local {
 3170            let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
 3171            let buffer_handle = self.buffer.read(cx).read(cx);
 3172
 3173            let mut text = String::new();
 3174            for (index, selection) in selections.iter().enumerate() {
 3175                let text_for_selection = buffer_handle
 3176                    .text_for_range(selection.start..selection.end)
 3177                    .collect::<String>();
 3178
 3179                text.push_str(&text_for_selection);
 3180                if index != selections.len() - 1 {
 3181                    text.push('\n');
 3182                }
 3183            }
 3184
 3185            if !text.is_empty() {
 3186                cx.write_to_primary(ClipboardItem::new_string(text));
 3187            }
 3188        }
 3189
 3190        let selection_anchors = self.selections.disjoint_anchors_arc();
 3191
 3192        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 3193            self.buffer.update(cx, |buffer, cx| {
 3194                buffer.set_active_selections(
 3195                    &selection_anchors,
 3196                    self.selections.line_mode(),
 3197                    self.cursor_shape,
 3198                    cx,
 3199                )
 3200            });
 3201        }
 3202        let display_map = self
 3203            .display_map
 3204            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3205        let buffer = display_map.buffer_snapshot();
 3206        if self.selections.count() == 1 {
 3207            self.add_selections_state = None;
 3208        }
 3209        self.select_next_state = None;
 3210        self.select_prev_state = None;
 3211        self.select_syntax_node_history.try_clear();
 3212        self.invalidate_autoclose_regions(&selection_anchors, buffer);
 3213        self.snippet_stack.invalidate(&selection_anchors, buffer);
 3214        self.take_rename(false, window, cx);
 3215
 3216        let newest_selection = self.selections.newest_anchor();
 3217        let new_cursor_position = newest_selection.head();
 3218        let selection_start = newest_selection.start;
 3219
 3220        if effects.nav_history.is_none() || effects.nav_history == Some(true) {
 3221            self.push_to_nav_history(
 3222                *old_cursor_position,
 3223                Some(new_cursor_position.to_point(buffer)),
 3224                false,
 3225                effects.nav_history == Some(true),
 3226                cx,
 3227            );
 3228        }
 3229
 3230        if local {
 3231            if let Some(buffer_id) = new_cursor_position.buffer_id {
 3232                self.register_buffer(buffer_id, cx);
 3233            }
 3234
 3235            let mut context_menu = self.context_menu.borrow_mut();
 3236            let completion_menu = match context_menu.as_ref() {
 3237                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 3238                Some(CodeContextMenu::CodeActions(_)) => {
 3239                    *context_menu = None;
 3240                    None
 3241                }
 3242                None => None,
 3243            };
 3244            let completion_position = completion_menu.map(|menu| menu.initial_position);
 3245            drop(context_menu);
 3246
 3247            if effects.completions
 3248                && let Some(completion_position) = completion_position
 3249            {
 3250                let start_offset = selection_start.to_offset(buffer);
 3251                let position_matches = start_offset == completion_position.to_offset(buffer);
 3252                let continue_showing = if position_matches {
 3253                    if self.snippet_stack.is_empty() {
 3254                        buffer.char_kind_before(start_offset, Some(CharScopeContext::Completion))
 3255                            == Some(CharKind::Word)
 3256                    } else {
 3257                        // Snippet choices can be shown even when the cursor is in whitespace.
 3258                        // Dismissing the menu with actions like backspace is handled by
 3259                        // invalidation regions.
 3260                        true
 3261                    }
 3262                } else {
 3263                    false
 3264                };
 3265
 3266                if continue_showing {
 3267                    self.open_or_update_completions_menu(None, None, false, window, cx);
 3268                } else {
 3269                    self.hide_context_menu(window, cx);
 3270                }
 3271            }
 3272
 3273            hide_hover(self, cx);
 3274
 3275            if old_cursor_position.to_display_point(&display_map).row()
 3276                != new_cursor_position.to_display_point(&display_map).row()
 3277            {
 3278                self.available_code_actions.take();
 3279            }
 3280            self.refresh_code_actions(window, cx);
 3281            self.refresh_document_highlights(cx);
 3282            refresh_linked_ranges(self, window, cx);
 3283
 3284            self.refresh_selected_text_highlights(false, window, cx);
 3285            self.refresh_matching_bracket_highlights(window, cx);
 3286            self.update_visible_edit_prediction(window, cx);
 3287            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 3288            self.inline_blame_popover.take();
 3289            if self.git_blame_inline_enabled {
 3290                self.start_inline_blame_timer(window, cx);
 3291            }
 3292        }
 3293
 3294        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 3295        cx.emit(EditorEvent::SelectionsChanged { local });
 3296
 3297        let selections = &self.selections.disjoint_anchors_arc();
 3298        if selections.len() == 1 {
 3299            cx.emit(SearchEvent::ActiveMatchChanged)
 3300        }
 3301        if local && let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 3302            let inmemory_selections = selections
 3303                .iter()
 3304                .map(|s| {
 3305                    text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 3306                        ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 3307                })
 3308                .collect();
 3309            self.update_restoration_data(cx, |data| {
 3310                data.selections = inmemory_selections;
 3311            });
 3312
 3313            if WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
 3314                && let Some(workspace_id) = self.workspace_serialization_id(cx)
 3315            {
 3316                let snapshot = self.buffer().read(cx).snapshot(cx);
 3317                let selections = selections.clone();
 3318                let background_executor = cx.background_executor().clone();
 3319                let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3320                self.serialize_selections = cx.background_spawn(async move {
 3321                    background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3322                    let db_selections = selections
 3323                        .iter()
 3324                        .map(|selection| {
 3325                            (
 3326                                selection.start.to_offset(&snapshot),
 3327                                selection.end.to_offset(&snapshot),
 3328                            )
 3329                        })
 3330                        .collect();
 3331
 3332                    DB.save_editor_selections(editor_id, workspace_id, db_selections)
 3333                        .await
 3334                        .with_context(|| {
 3335                            format!(
 3336                                "persisting editor selections for editor {editor_id}, \
 3337                                workspace {workspace_id:?}"
 3338                            )
 3339                        })
 3340                        .log_err();
 3341                });
 3342            }
 3343        }
 3344
 3345        cx.notify();
 3346    }
 3347
 3348    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 3349        use text::ToOffset as _;
 3350        use text::ToPoint as _;
 3351
 3352        if self.mode.is_minimap()
 3353            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 3354        {
 3355            return;
 3356        }
 3357
 3358        if !self.buffer().read(cx).is_singleton() {
 3359            return;
 3360        }
 3361
 3362        let display_snapshot = self
 3363            .display_map
 3364            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3365        let Some((.., snapshot)) = display_snapshot.buffer_snapshot().as_singleton() else {
 3366            return;
 3367        };
 3368        let inmemory_folds = display_snapshot
 3369            .folds_in_range(0..display_snapshot.buffer_snapshot().len())
 3370            .map(|fold| {
 3371                fold.range.start.text_anchor.to_point(&snapshot)
 3372                    ..fold.range.end.text_anchor.to_point(&snapshot)
 3373            })
 3374            .collect();
 3375        self.update_restoration_data(cx, |data| {
 3376            data.folds = inmemory_folds;
 3377        });
 3378
 3379        let Some(workspace_id) = self.workspace_serialization_id(cx) else {
 3380            return;
 3381        };
 3382        let background_executor = cx.background_executor().clone();
 3383        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3384        let db_folds = display_snapshot
 3385            .folds_in_range(0..display_snapshot.buffer_snapshot().len())
 3386            .map(|fold| {
 3387                (
 3388                    fold.range.start.text_anchor.to_offset(&snapshot),
 3389                    fold.range.end.text_anchor.to_offset(&snapshot),
 3390                )
 3391            })
 3392            .collect();
 3393        self.serialize_folds = cx.background_spawn(async move {
 3394            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3395            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 3396                .await
 3397                .with_context(|| {
 3398                    format!(
 3399                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 3400                    )
 3401                })
 3402                .log_err();
 3403        });
 3404    }
 3405
 3406    pub fn sync_selections(
 3407        &mut self,
 3408        other: Entity<Editor>,
 3409        cx: &mut Context<Self>,
 3410    ) -> gpui::Subscription {
 3411        let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3412        if !other_selections.is_empty() {
 3413            self.selections
 3414                .change_with(&self.display_snapshot(cx), |selections| {
 3415                    selections.select_anchors(other_selections);
 3416                });
 3417        }
 3418
 3419        let other_subscription = cx.subscribe(&other, |this, other, other_evt, cx| {
 3420            if let EditorEvent::SelectionsChanged { local: true } = other_evt {
 3421                let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3422                if other_selections.is_empty() {
 3423                    return;
 3424                }
 3425                let snapshot = this.display_snapshot(cx);
 3426                this.selections.change_with(&snapshot, |selections| {
 3427                    selections.select_anchors(other_selections);
 3428                });
 3429            }
 3430        });
 3431
 3432        let this_subscription = cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| {
 3433            if let EditorEvent::SelectionsChanged { local: true } = this_evt {
 3434                let these_selections = this.selections.disjoint_anchors().to_vec();
 3435                if these_selections.is_empty() {
 3436                    return;
 3437                }
 3438                other.update(cx, |other_editor, cx| {
 3439                    let snapshot = other_editor.display_snapshot(cx);
 3440                    other_editor
 3441                        .selections
 3442                        .change_with(&snapshot, |selections| {
 3443                            selections.select_anchors(these_selections);
 3444                        })
 3445                });
 3446            }
 3447        });
 3448
 3449        Subscription::join(other_subscription, this_subscription)
 3450    }
 3451
 3452    fn unfold_buffers_with_selections(&mut self, cx: &mut Context<Self>) {
 3453        if self.buffer().read(cx).is_singleton() {
 3454            return;
 3455        }
 3456        let snapshot = self.buffer.read(cx).snapshot(cx);
 3457        let buffer_ids: HashSet<BufferId> = self
 3458            .selections
 3459            .disjoint_anchor_ranges()
 3460            .flat_map(|range| snapshot.buffer_ids_for_range(range))
 3461            .collect();
 3462        for buffer_id in buffer_ids {
 3463            self.unfold_buffer(buffer_id, cx);
 3464        }
 3465    }
 3466
 3467    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 3468    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 3469    /// effects of selection change occur at the end of the transaction.
 3470    pub fn change_selections<R>(
 3471        &mut self,
 3472        effects: SelectionEffects,
 3473        window: &mut Window,
 3474        cx: &mut Context<Self>,
 3475        change: impl FnOnce(&mut MutableSelectionsCollection<'_, '_>) -> R,
 3476    ) -> R {
 3477        let snapshot = self.display_snapshot(cx);
 3478        if let Some(state) = &mut self.deferred_selection_effects_state {
 3479            state.effects.scroll = effects.scroll.or(state.effects.scroll);
 3480            state.effects.completions = effects.completions;
 3481            state.effects.nav_history = effects.nav_history.or(state.effects.nav_history);
 3482            let (changed, result) = self.selections.change_with(&snapshot, change);
 3483            state.changed |= changed;
 3484            return result;
 3485        }
 3486        let mut state = DeferredSelectionEffectsState {
 3487            changed: false,
 3488            effects,
 3489            old_cursor_position: self.selections.newest_anchor().head(),
 3490            history_entry: SelectionHistoryEntry {
 3491                selections: self.selections.disjoint_anchors_arc(),
 3492                select_next_state: self.select_next_state.clone(),
 3493                select_prev_state: self.select_prev_state.clone(),
 3494                add_selections_state: self.add_selections_state.clone(),
 3495            },
 3496        };
 3497        let (changed, result) = self.selections.change_with(&snapshot, change);
 3498        state.changed = state.changed || changed;
 3499        if self.defer_selection_effects {
 3500            self.deferred_selection_effects_state = Some(state);
 3501        } else {
 3502            self.apply_selection_effects(state, window, cx);
 3503        }
 3504        result
 3505    }
 3506
 3507    /// Defers the effects of selection change, so that the effects of multiple calls to
 3508    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3509    /// to selection history and the state of popovers based on selection position aren't
 3510    /// erroneously updated.
 3511    pub fn with_selection_effects_deferred<R>(
 3512        &mut self,
 3513        window: &mut Window,
 3514        cx: &mut Context<Self>,
 3515        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3516    ) -> R {
 3517        let already_deferred = self.defer_selection_effects;
 3518        self.defer_selection_effects = true;
 3519        let result = update(self, window, cx);
 3520        if !already_deferred {
 3521            self.defer_selection_effects = false;
 3522            if let Some(state) = self.deferred_selection_effects_state.take() {
 3523                self.apply_selection_effects(state, window, cx);
 3524            }
 3525        }
 3526        result
 3527    }
 3528
 3529    fn apply_selection_effects(
 3530        &mut self,
 3531        state: DeferredSelectionEffectsState,
 3532        window: &mut Window,
 3533        cx: &mut Context<Self>,
 3534    ) {
 3535        if state.changed {
 3536            self.selection_history.push(state.history_entry);
 3537
 3538            if let Some(autoscroll) = state.effects.scroll {
 3539                self.request_autoscroll(autoscroll, cx);
 3540            }
 3541
 3542            let old_cursor_position = &state.old_cursor_position;
 3543
 3544            self.selections_did_change(true, old_cursor_position, state.effects, window, cx);
 3545
 3546            if self.should_open_signature_help_automatically(old_cursor_position, cx) {
 3547                self.show_signature_help(&ShowSignatureHelp, window, cx);
 3548            }
 3549        }
 3550    }
 3551
 3552    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3553    where
 3554        I: IntoIterator<Item = (Range<S>, T)>,
 3555        S: ToOffset,
 3556        T: Into<Arc<str>>,
 3557    {
 3558        if self.read_only(cx) {
 3559            return;
 3560        }
 3561
 3562        self.buffer
 3563            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3564    }
 3565
 3566    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3567    where
 3568        I: IntoIterator<Item = (Range<S>, T)>,
 3569        S: ToOffset,
 3570        T: Into<Arc<str>>,
 3571    {
 3572        if self.read_only(cx) {
 3573            return;
 3574        }
 3575
 3576        self.buffer.update(cx, |buffer, cx| {
 3577            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3578        });
 3579    }
 3580
 3581    pub fn edit_with_block_indent<I, S, T>(
 3582        &mut self,
 3583        edits: I,
 3584        original_indent_columns: Vec<Option<u32>>,
 3585        cx: &mut Context<Self>,
 3586    ) where
 3587        I: IntoIterator<Item = (Range<S>, T)>,
 3588        S: ToOffset,
 3589        T: Into<Arc<str>>,
 3590    {
 3591        if self.read_only(cx) {
 3592            return;
 3593        }
 3594
 3595        self.buffer.update(cx, |buffer, cx| {
 3596            buffer.edit(
 3597                edits,
 3598                Some(AutoindentMode::Block {
 3599                    original_indent_columns,
 3600                }),
 3601                cx,
 3602            )
 3603        });
 3604    }
 3605
 3606    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3607        self.hide_context_menu(window, cx);
 3608
 3609        match phase {
 3610            SelectPhase::Begin {
 3611                position,
 3612                add,
 3613                click_count,
 3614            } => self.begin_selection(position, add, click_count, window, cx),
 3615            SelectPhase::BeginColumnar {
 3616                position,
 3617                goal_column,
 3618                reset,
 3619                mode,
 3620            } => self.begin_columnar_selection(position, goal_column, reset, mode, window, cx),
 3621            SelectPhase::Extend {
 3622                position,
 3623                click_count,
 3624            } => self.extend_selection(position, click_count, window, cx),
 3625            SelectPhase::Update {
 3626                position,
 3627                goal_column,
 3628                scroll_delta,
 3629            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3630            SelectPhase::End => self.end_selection(window, cx),
 3631        }
 3632    }
 3633
 3634    fn extend_selection(
 3635        &mut self,
 3636        position: DisplayPoint,
 3637        click_count: usize,
 3638        window: &mut Window,
 3639        cx: &mut Context<Self>,
 3640    ) {
 3641        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3642        let tail = self.selections.newest::<usize>(&display_map).tail();
 3643        let click_count = click_count.max(match self.selections.select_mode() {
 3644            SelectMode::Character => 1,
 3645            SelectMode::Word(_) => 2,
 3646            SelectMode::Line(_) => 3,
 3647            SelectMode::All => 4,
 3648        });
 3649        self.begin_selection(position, false, click_count, window, cx);
 3650
 3651        let tail_anchor = display_map.buffer_snapshot().anchor_before(tail);
 3652
 3653        let current_selection = match self.selections.select_mode() {
 3654            SelectMode::Character | SelectMode::All => tail_anchor..tail_anchor,
 3655            SelectMode::Word(range) | SelectMode::Line(range) => range.clone(),
 3656        };
 3657
 3658        let mut pending_selection = self
 3659            .selections
 3660            .pending_anchor()
 3661            .cloned()
 3662            .expect("extend_selection not called with pending selection");
 3663
 3664        if pending_selection
 3665            .start
 3666            .cmp(&current_selection.start, display_map.buffer_snapshot())
 3667            == Ordering::Greater
 3668        {
 3669            pending_selection.start = current_selection.start;
 3670        }
 3671        if pending_selection
 3672            .end
 3673            .cmp(&current_selection.end, display_map.buffer_snapshot())
 3674            == Ordering::Less
 3675        {
 3676            pending_selection.end = current_selection.end;
 3677            pending_selection.reversed = true;
 3678        }
 3679
 3680        let mut pending_mode = self.selections.pending_mode().unwrap();
 3681        match &mut pending_mode {
 3682            SelectMode::Word(range) | SelectMode::Line(range) => *range = current_selection,
 3683            _ => {}
 3684        }
 3685
 3686        let effects = if EditorSettings::get_global(cx).autoscroll_on_clicks {
 3687            SelectionEffects::scroll(Autoscroll::fit())
 3688        } else {
 3689            SelectionEffects::no_scroll()
 3690        };
 3691
 3692        self.change_selections(effects, window, cx, |s| {
 3693            s.set_pending(pending_selection.clone(), pending_mode);
 3694            s.set_is_extending(true);
 3695        });
 3696    }
 3697
 3698    fn begin_selection(
 3699        &mut self,
 3700        position: DisplayPoint,
 3701        add: bool,
 3702        click_count: usize,
 3703        window: &mut Window,
 3704        cx: &mut Context<Self>,
 3705    ) {
 3706        if !self.focus_handle.is_focused(window) {
 3707            self.last_focused_descendant = None;
 3708            window.focus(&self.focus_handle);
 3709        }
 3710
 3711        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3712        let buffer = display_map.buffer_snapshot();
 3713        let position = display_map.clip_point(position, Bias::Left);
 3714
 3715        let start;
 3716        let end;
 3717        let mode;
 3718        let mut auto_scroll;
 3719        match click_count {
 3720            1 => {
 3721                start = buffer.anchor_before(position.to_point(&display_map));
 3722                end = start;
 3723                mode = SelectMode::Character;
 3724                auto_scroll = true;
 3725            }
 3726            2 => {
 3727                let position = display_map
 3728                    .clip_point(position, Bias::Left)
 3729                    .to_offset(&display_map, Bias::Left);
 3730                let (range, _) = buffer.surrounding_word(position, None);
 3731                start = buffer.anchor_before(range.start);
 3732                end = buffer.anchor_before(range.end);
 3733                mode = SelectMode::Word(start..end);
 3734                auto_scroll = true;
 3735            }
 3736            3 => {
 3737                let position = display_map
 3738                    .clip_point(position, Bias::Left)
 3739                    .to_point(&display_map);
 3740                let line_start = display_map.prev_line_boundary(position).0;
 3741                let next_line_start = buffer.clip_point(
 3742                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3743                    Bias::Left,
 3744                );
 3745                start = buffer.anchor_before(line_start);
 3746                end = buffer.anchor_before(next_line_start);
 3747                mode = SelectMode::Line(start..end);
 3748                auto_scroll = true;
 3749            }
 3750            _ => {
 3751                start = buffer.anchor_before(0);
 3752                end = buffer.anchor_before(buffer.len());
 3753                mode = SelectMode::All;
 3754                auto_scroll = false;
 3755            }
 3756        }
 3757        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3758
 3759        let point_to_delete: Option<usize> = {
 3760            let selected_points: Vec<Selection<Point>> =
 3761                self.selections.disjoint_in_range(start..end, &display_map);
 3762
 3763            if !add || click_count > 1 {
 3764                None
 3765            } else if !selected_points.is_empty() {
 3766                Some(selected_points[0].id)
 3767            } else {
 3768                let clicked_point_already_selected =
 3769                    self.selections.disjoint_anchors().iter().find(|selection| {
 3770                        selection.start.to_point(buffer) == start.to_point(buffer)
 3771                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3772                    });
 3773
 3774                clicked_point_already_selected.map(|selection| selection.id)
 3775            }
 3776        };
 3777
 3778        let selections_count = self.selections.count();
 3779        let effects = if auto_scroll {
 3780            SelectionEffects::default()
 3781        } else {
 3782            SelectionEffects::no_scroll()
 3783        };
 3784
 3785        self.change_selections(effects, window, cx, |s| {
 3786            if let Some(point_to_delete) = point_to_delete {
 3787                s.delete(point_to_delete);
 3788
 3789                if selections_count == 1 {
 3790                    s.set_pending_anchor_range(start..end, mode);
 3791                }
 3792            } else {
 3793                if !add {
 3794                    s.clear_disjoint();
 3795                }
 3796
 3797                s.set_pending_anchor_range(start..end, mode);
 3798            }
 3799        });
 3800    }
 3801
 3802    fn begin_columnar_selection(
 3803        &mut self,
 3804        position: DisplayPoint,
 3805        goal_column: u32,
 3806        reset: bool,
 3807        mode: ColumnarMode,
 3808        window: &mut Window,
 3809        cx: &mut Context<Self>,
 3810    ) {
 3811        if !self.focus_handle.is_focused(window) {
 3812            self.last_focused_descendant = None;
 3813            window.focus(&self.focus_handle);
 3814        }
 3815
 3816        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3817
 3818        if reset {
 3819            let pointer_position = display_map
 3820                .buffer_snapshot()
 3821                .anchor_before(position.to_point(&display_map));
 3822
 3823            self.change_selections(
 3824                SelectionEffects::scroll(Autoscroll::newest()),
 3825                window,
 3826                cx,
 3827                |s| {
 3828                    s.clear_disjoint();
 3829                    s.set_pending_anchor_range(
 3830                        pointer_position..pointer_position,
 3831                        SelectMode::Character,
 3832                    );
 3833                },
 3834            );
 3835        };
 3836
 3837        let tail = self.selections.newest::<Point>(&display_map).tail();
 3838        let selection_anchor = display_map.buffer_snapshot().anchor_before(tail);
 3839        self.columnar_selection_state = match mode {
 3840            ColumnarMode::FromMouse => Some(ColumnarSelectionState::FromMouse {
 3841                selection_tail: selection_anchor,
 3842                display_point: if reset {
 3843                    if position.column() != goal_column {
 3844                        Some(DisplayPoint::new(position.row(), goal_column))
 3845                    } else {
 3846                        None
 3847                    }
 3848                } else {
 3849                    None
 3850                },
 3851            }),
 3852            ColumnarMode::FromSelection => Some(ColumnarSelectionState::FromSelection {
 3853                selection_tail: selection_anchor,
 3854            }),
 3855        };
 3856
 3857        if !reset {
 3858            self.select_columns(position, goal_column, &display_map, window, cx);
 3859        }
 3860    }
 3861
 3862    fn update_selection(
 3863        &mut self,
 3864        position: DisplayPoint,
 3865        goal_column: u32,
 3866        scroll_delta: gpui::Point<f32>,
 3867        window: &mut Window,
 3868        cx: &mut Context<Self>,
 3869    ) {
 3870        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3871
 3872        if self.columnar_selection_state.is_some() {
 3873            self.select_columns(position, goal_column, &display_map, window, cx);
 3874        } else if let Some(mut pending) = self.selections.pending_anchor().cloned() {
 3875            let buffer = display_map.buffer_snapshot();
 3876            let head;
 3877            let tail;
 3878            let mode = self.selections.pending_mode().unwrap();
 3879            match &mode {
 3880                SelectMode::Character => {
 3881                    head = position.to_point(&display_map);
 3882                    tail = pending.tail().to_point(buffer);
 3883                }
 3884                SelectMode::Word(original_range) => {
 3885                    let offset = display_map
 3886                        .clip_point(position, Bias::Left)
 3887                        .to_offset(&display_map, Bias::Left);
 3888                    let original_range = original_range.to_offset(buffer);
 3889
 3890                    let head_offset = if buffer.is_inside_word(offset, None)
 3891                        || original_range.contains(&offset)
 3892                    {
 3893                        let (word_range, _) = buffer.surrounding_word(offset, None);
 3894                        if word_range.start < original_range.start {
 3895                            word_range.start
 3896                        } else {
 3897                            word_range.end
 3898                        }
 3899                    } else {
 3900                        offset
 3901                    };
 3902
 3903                    head = head_offset.to_point(buffer);
 3904                    if head_offset <= original_range.start {
 3905                        tail = original_range.end.to_point(buffer);
 3906                    } else {
 3907                        tail = original_range.start.to_point(buffer);
 3908                    }
 3909                }
 3910                SelectMode::Line(original_range) => {
 3911                    let original_range = original_range.to_point(display_map.buffer_snapshot());
 3912
 3913                    let position = display_map
 3914                        .clip_point(position, Bias::Left)
 3915                        .to_point(&display_map);
 3916                    let line_start = display_map.prev_line_boundary(position).0;
 3917                    let next_line_start = buffer.clip_point(
 3918                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3919                        Bias::Left,
 3920                    );
 3921
 3922                    if line_start < original_range.start {
 3923                        head = line_start
 3924                    } else {
 3925                        head = next_line_start
 3926                    }
 3927
 3928                    if head <= original_range.start {
 3929                        tail = original_range.end;
 3930                    } else {
 3931                        tail = original_range.start;
 3932                    }
 3933                }
 3934                SelectMode::All => {
 3935                    return;
 3936                }
 3937            };
 3938
 3939            if head < tail {
 3940                pending.start = buffer.anchor_before(head);
 3941                pending.end = buffer.anchor_before(tail);
 3942                pending.reversed = true;
 3943            } else {
 3944                pending.start = buffer.anchor_before(tail);
 3945                pending.end = buffer.anchor_before(head);
 3946                pending.reversed = false;
 3947            }
 3948
 3949            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3950                s.set_pending(pending.clone(), mode);
 3951            });
 3952        } else {
 3953            log::error!("update_selection dispatched with no pending selection");
 3954            return;
 3955        }
 3956
 3957        self.apply_scroll_delta(scroll_delta, window, cx);
 3958        cx.notify();
 3959    }
 3960
 3961    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3962        self.columnar_selection_state.take();
 3963        if let Some(pending_mode) = self.selections.pending_mode() {
 3964            let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
 3965            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3966                s.select(selections);
 3967                s.clear_pending();
 3968                if s.is_extending() {
 3969                    s.set_is_extending(false);
 3970                } else {
 3971                    s.set_select_mode(pending_mode);
 3972                }
 3973            });
 3974        }
 3975    }
 3976
 3977    fn select_columns(
 3978        &mut self,
 3979        head: DisplayPoint,
 3980        goal_column: u32,
 3981        display_map: &DisplaySnapshot,
 3982        window: &mut Window,
 3983        cx: &mut Context<Self>,
 3984    ) {
 3985        let Some(columnar_state) = self.columnar_selection_state.as_ref() else {
 3986            return;
 3987        };
 3988
 3989        let tail = match columnar_state {
 3990            ColumnarSelectionState::FromMouse {
 3991                selection_tail,
 3992                display_point,
 3993            } => display_point.unwrap_or_else(|| selection_tail.to_display_point(display_map)),
 3994            ColumnarSelectionState::FromSelection { selection_tail } => {
 3995                selection_tail.to_display_point(display_map)
 3996            }
 3997        };
 3998
 3999        let start_row = cmp::min(tail.row(), head.row());
 4000        let end_row = cmp::max(tail.row(), head.row());
 4001        let start_column = cmp::min(tail.column(), goal_column);
 4002        let end_column = cmp::max(tail.column(), goal_column);
 4003        let reversed = start_column < tail.column();
 4004
 4005        let selection_ranges = (start_row.0..=end_row.0)
 4006            .map(DisplayRow)
 4007            .filter_map(|row| {
 4008                if (matches!(columnar_state, ColumnarSelectionState::FromMouse { .. })
 4009                    || start_column <= display_map.line_len(row))
 4010                    && !display_map.is_block_line(row)
 4011                {
 4012                    let start = display_map
 4013                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 4014                        .to_point(display_map);
 4015                    let end = display_map
 4016                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 4017                        .to_point(display_map);
 4018                    if reversed {
 4019                        Some(end..start)
 4020                    } else {
 4021                        Some(start..end)
 4022                    }
 4023                } else {
 4024                    None
 4025                }
 4026            })
 4027            .collect::<Vec<_>>();
 4028        if selection_ranges.is_empty() {
 4029            return;
 4030        }
 4031
 4032        let ranges = match columnar_state {
 4033            ColumnarSelectionState::FromMouse { .. } => {
 4034                let mut non_empty_ranges = selection_ranges
 4035                    .iter()
 4036                    .filter(|selection_range| selection_range.start != selection_range.end)
 4037                    .peekable();
 4038                if non_empty_ranges.peek().is_some() {
 4039                    non_empty_ranges.cloned().collect()
 4040                } else {
 4041                    selection_ranges
 4042                }
 4043            }
 4044            _ => selection_ranges,
 4045        };
 4046
 4047        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 4048            s.select_ranges(ranges);
 4049        });
 4050        cx.notify();
 4051    }
 4052
 4053    pub fn has_non_empty_selection(&self, snapshot: &DisplaySnapshot) -> bool {
 4054        self.selections
 4055            .all_adjusted(snapshot)
 4056            .iter()
 4057            .any(|selection| !selection.is_empty())
 4058    }
 4059
 4060    pub fn has_pending_nonempty_selection(&self) -> bool {
 4061        let pending_nonempty_selection = match self.selections.pending_anchor() {
 4062            Some(Selection { start, end, .. }) => start != end,
 4063            None => false,
 4064        };
 4065
 4066        pending_nonempty_selection
 4067            || (self.columnar_selection_state.is_some()
 4068                && self.selections.disjoint_anchors().len() > 1)
 4069    }
 4070
 4071    pub fn has_pending_selection(&self) -> bool {
 4072        self.selections.pending_anchor().is_some() || self.columnar_selection_state.is_some()
 4073    }
 4074
 4075    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 4076        self.selection_mark_mode = false;
 4077        self.selection_drag_state = SelectionDragState::None;
 4078
 4079        if self.dismiss_menus_and_popups(true, window, cx) {
 4080            cx.notify();
 4081            return;
 4082        }
 4083        if self.clear_expanded_diff_hunks(cx) {
 4084            cx.notify();
 4085            return;
 4086        }
 4087        if self.show_git_blame_gutter {
 4088            self.show_git_blame_gutter = false;
 4089            cx.notify();
 4090            return;
 4091        }
 4092
 4093        if self.mode.is_full()
 4094            && self.change_selections(Default::default(), window, cx, |s| s.try_cancel())
 4095        {
 4096            cx.notify();
 4097            return;
 4098        }
 4099
 4100        cx.propagate();
 4101    }
 4102
 4103    pub fn dismiss_menus_and_popups(
 4104        &mut self,
 4105        is_user_requested: bool,
 4106        window: &mut Window,
 4107        cx: &mut Context<Self>,
 4108    ) -> bool {
 4109        if self.take_rename(false, window, cx).is_some() {
 4110            return true;
 4111        }
 4112
 4113        if self.hide_blame_popover(true, cx) {
 4114            return true;
 4115        }
 4116
 4117        if hide_hover(self, cx) {
 4118            return true;
 4119        }
 4120
 4121        if self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape) {
 4122            return true;
 4123        }
 4124
 4125        if self.hide_context_menu(window, cx).is_some() {
 4126            return true;
 4127        }
 4128
 4129        if self.mouse_context_menu.take().is_some() {
 4130            return true;
 4131        }
 4132
 4133        if is_user_requested && self.discard_edit_prediction(true, cx) {
 4134            return true;
 4135        }
 4136
 4137        if self.snippet_stack.pop().is_some() {
 4138            return true;
 4139        }
 4140
 4141        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 4142            self.dismiss_diagnostics(cx);
 4143            return true;
 4144        }
 4145
 4146        false
 4147    }
 4148
 4149    fn linked_editing_ranges_for(
 4150        &self,
 4151        selection: Range<text::Anchor>,
 4152        cx: &App,
 4153    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 4154        if self.linked_edit_ranges.is_empty() {
 4155            return None;
 4156        }
 4157        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 4158            selection.end.buffer_id.and_then(|end_buffer_id| {
 4159                if selection.start.buffer_id != Some(end_buffer_id) {
 4160                    return None;
 4161                }
 4162                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 4163                let snapshot = buffer.read(cx).snapshot();
 4164                self.linked_edit_ranges
 4165                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 4166                    .map(|ranges| (ranges, snapshot, buffer))
 4167            })?;
 4168        use text::ToOffset as TO;
 4169        // find offset from the start of current range to current cursor position
 4170        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 4171
 4172        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 4173        let start_difference = start_offset - start_byte_offset;
 4174        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 4175        let end_difference = end_offset - start_byte_offset;
 4176        // Current range has associated linked ranges.
 4177        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4178        for range in linked_ranges.iter() {
 4179            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 4180            let end_offset = start_offset + end_difference;
 4181            let start_offset = start_offset + start_difference;
 4182            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 4183                continue;
 4184            }
 4185            if self.selections.disjoint_anchor_ranges().any(|s| {
 4186                if s.start.buffer_id != selection.start.buffer_id
 4187                    || s.end.buffer_id != selection.end.buffer_id
 4188                {
 4189                    return false;
 4190                }
 4191                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 4192                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 4193            }) {
 4194                continue;
 4195            }
 4196            let start = buffer_snapshot.anchor_after(start_offset);
 4197            let end = buffer_snapshot.anchor_after(end_offset);
 4198            linked_edits
 4199                .entry(buffer.clone())
 4200                .or_default()
 4201                .push(start..end);
 4202        }
 4203        Some(linked_edits)
 4204    }
 4205
 4206    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4207        let text: Arc<str> = text.into();
 4208
 4209        if self.read_only(cx) {
 4210            return;
 4211        }
 4212
 4213        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4214
 4215        self.unfold_buffers_with_selections(cx);
 4216
 4217        let selections = self.selections.all_adjusted(&self.display_snapshot(cx));
 4218        let mut bracket_inserted = false;
 4219        let mut edits = Vec::new();
 4220        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4221        let mut new_selections = Vec::with_capacity(selections.len());
 4222        let mut new_autoclose_regions = Vec::new();
 4223        let snapshot = self.buffer.read(cx).read(cx);
 4224        let mut clear_linked_edit_ranges = false;
 4225
 4226        for (selection, autoclose_region) in
 4227            self.selections_with_autoclose_regions(selections, &snapshot)
 4228        {
 4229            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 4230                // Determine if the inserted text matches the opening or closing
 4231                // bracket of any of this language's bracket pairs.
 4232                let mut bracket_pair = None;
 4233                let mut is_bracket_pair_start = false;
 4234                let mut is_bracket_pair_end = false;
 4235                if !text.is_empty() {
 4236                    let mut bracket_pair_matching_end = None;
 4237                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 4238                    //  and they are removing the character that triggered IME popup.
 4239                    for (pair, enabled) in scope.brackets() {
 4240                        if !pair.close && !pair.surround {
 4241                            continue;
 4242                        }
 4243
 4244                        if enabled && pair.start.ends_with(text.as_ref()) {
 4245                            let prefix_len = pair.start.len() - text.len();
 4246                            let preceding_text_matches_prefix = prefix_len == 0
 4247                                || (selection.start.column >= (prefix_len as u32)
 4248                                    && snapshot.contains_str_at(
 4249                                        Point::new(
 4250                                            selection.start.row,
 4251                                            selection.start.column - (prefix_len as u32),
 4252                                        ),
 4253                                        &pair.start[..prefix_len],
 4254                                    ));
 4255                            if preceding_text_matches_prefix {
 4256                                bracket_pair = Some(pair.clone());
 4257                                is_bracket_pair_start = true;
 4258                                break;
 4259                            }
 4260                        }
 4261                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 4262                        {
 4263                            // take first bracket pair matching end, but don't break in case a later bracket
 4264                            // pair matches start
 4265                            bracket_pair_matching_end = Some(pair.clone());
 4266                        }
 4267                    }
 4268                    if let Some(end) = bracket_pair_matching_end
 4269                        && bracket_pair.is_none()
 4270                    {
 4271                        bracket_pair = Some(end);
 4272                        is_bracket_pair_end = true;
 4273                    }
 4274                }
 4275
 4276                if let Some(bracket_pair) = bracket_pair {
 4277                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 4278                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 4279                    let auto_surround =
 4280                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 4281                    if selection.is_empty() {
 4282                        if is_bracket_pair_start {
 4283                            // If the inserted text is a suffix of an opening bracket and the
 4284                            // selection is preceded by the rest of the opening bracket, then
 4285                            // insert the closing bracket.
 4286                            let following_text_allows_autoclose = snapshot
 4287                                .chars_at(selection.start)
 4288                                .next()
 4289                                .is_none_or(|c| scope.should_autoclose_before(c));
 4290
 4291                            let preceding_text_allows_autoclose = selection.start.column == 0
 4292                                || snapshot
 4293                                    .reversed_chars_at(selection.start)
 4294                                    .next()
 4295                                    .is_none_or(|c| {
 4296                                        bracket_pair.start != bracket_pair.end
 4297                                            || !snapshot
 4298                                                .char_classifier_at(selection.start)
 4299                                                .is_word(c)
 4300                                    });
 4301
 4302                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 4303                                && bracket_pair.start.len() == 1
 4304                            {
 4305                                let target = bracket_pair.start.chars().next().unwrap();
 4306                                let current_line_count = snapshot
 4307                                    .reversed_chars_at(selection.start)
 4308                                    .take_while(|&c| c != '\n')
 4309                                    .filter(|&c| c == target)
 4310                                    .count();
 4311                                current_line_count % 2 == 1
 4312                            } else {
 4313                                false
 4314                            };
 4315
 4316                            if autoclose
 4317                                && bracket_pair.close
 4318                                && following_text_allows_autoclose
 4319                                && preceding_text_allows_autoclose
 4320                                && !is_closing_quote
 4321                            {
 4322                                let anchor = snapshot.anchor_before(selection.end);
 4323                                new_selections.push((selection.map(|_| anchor), text.len()));
 4324                                new_autoclose_regions.push((
 4325                                    anchor,
 4326                                    text.len(),
 4327                                    selection.id,
 4328                                    bracket_pair.clone(),
 4329                                ));
 4330                                edits.push((
 4331                                    selection.range(),
 4332                                    format!("{}{}", text, bracket_pair.end).into(),
 4333                                ));
 4334                                bracket_inserted = true;
 4335                                continue;
 4336                            }
 4337                        }
 4338
 4339                        if let Some(region) = autoclose_region {
 4340                            // If the selection is followed by an auto-inserted closing bracket,
 4341                            // then don't insert that closing bracket again; just move the selection
 4342                            // past the closing bracket.
 4343                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 4344                                && text.as_ref() == region.pair.end.as_str()
 4345                                && snapshot.contains_str_at(region.range.end, text.as_ref());
 4346                            if should_skip {
 4347                                let anchor = snapshot.anchor_after(selection.end);
 4348                                new_selections
 4349                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 4350                                continue;
 4351                            }
 4352                        }
 4353
 4354                        let always_treat_brackets_as_autoclosed = snapshot
 4355                            .language_settings_at(selection.start, cx)
 4356                            .always_treat_brackets_as_autoclosed;
 4357                        if always_treat_brackets_as_autoclosed
 4358                            && is_bracket_pair_end
 4359                            && snapshot.contains_str_at(selection.end, text.as_ref())
 4360                        {
 4361                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 4362                            // and the inserted text is a closing bracket and the selection is followed
 4363                            // by the closing bracket then move the selection past the closing bracket.
 4364                            let anchor = snapshot.anchor_after(selection.end);
 4365                            new_selections.push((selection.map(|_| anchor), text.len()));
 4366                            continue;
 4367                        }
 4368                    }
 4369                    // If an opening bracket is 1 character long and is typed while
 4370                    // text is selected, then surround that text with the bracket pair.
 4371                    else if auto_surround
 4372                        && bracket_pair.surround
 4373                        && is_bracket_pair_start
 4374                        && bracket_pair.start.chars().count() == 1
 4375                    {
 4376                        edits.push((selection.start..selection.start, text.clone()));
 4377                        edits.push((
 4378                            selection.end..selection.end,
 4379                            bracket_pair.end.as_str().into(),
 4380                        ));
 4381                        bracket_inserted = true;
 4382                        new_selections.push((
 4383                            Selection {
 4384                                id: selection.id,
 4385                                start: snapshot.anchor_after(selection.start),
 4386                                end: snapshot.anchor_before(selection.end),
 4387                                reversed: selection.reversed,
 4388                                goal: selection.goal,
 4389                            },
 4390                            0,
 4391                        ));
 4392                        continue;
 4393                    }
 4394                }
 4395            }
 4396
 4397            if self.auto_replace_emoji_shortcode
 4398                && selection.is_empty()
 4399                && text.as_ref().ends_with(':')
 4400                && let Some(possible_emoji_short_code) =
 4401                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 4402                && !possible_emoji_short_code.is_empty()
 4403                && let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code)
 4404            {
 4405                let emoji_shortcode_start = Point::new(
 4406                    selection.start.row,
 4407                    selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 4408                );
 4409
 4410                // Remove shortcode from buffer
 4411                edits.push((
 4412                    emoji_shortcode_start..selection.start,
 4413                    "".to_string().into(),
 4414                ));
 4415                new_selections.push((
 4416                    Selection {
 4417                        id: selection.id,
 4418                        start: snapshot.anchor_after(emoji_shortcode_start),
 4419                        end: snapshot.anchor_before(selection.start),
 4420                        reversed: selection.reversed,
 4421                        goal: selection.goal,
 4422                    },
 4423                    0,
 4424                ));
 4425
 4426                // Insert emoji
 4427                let selection_start_anchor = snapshot.anchor_after(selection.start);
 4428                new_selections.push((selection.map(|_| selection_start_anchor), 0));
 4429                edits.push((selection.start..selection.end, emoji.to_string().into()));
 4430
 4431                continue;
 4432            }
 4433
 4434            // If not handling any auto-close operation, then just replace the selected
 4435            // text with the given input and move the selection to the end of the
 4436            // newly inserted text.
 4437            let anchor = snapshot.anchor_after(selection.end);
 4438            if !self.linked_edit_ranges.is_empty() {
 4439                let start_anchor = snapshot.anchor_before(selection.start);
 4440
 4441                let is_word_char = text.chars().next().is_none_or(|char| {
 4442                    let classifier = snapshot
 4443                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 4444                        .scope_context(Some(CharScopeContext::LinkedEdit));
 4445                    classifier.is_word(char)
 4446                });
 4447
 4448                if is_word_char {
 4449                    if let Some(ranges) = self
 4450                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 4451                    {
 4452                        for (buffer, edits) in ranges {
 4453                            linked_edits
 4454                                .entry(buffer.clone())
 4455                                .or_default()
 4456                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 4457                        }
 4458                    }
 4459                } else {
 4460                    clear_linked_edit_ranges = true;
 4461                }
 4462            }
 4463
 4464            new_selections.push((selection.map(|_| anchor), 0));
 4465            edits.push((selection.start..selection.end, text.clone()));
 4466        }
 4467
 4468        drop(snapshot);
 4469
 4470        self.transact(window, cx, |this, window, cx| {
 4471            if clear_linked_edit_ranges {
 4472                this.linked_edit_ranges.clear();
 4473            }
 4474            let initial_buffer_versions =
 4475                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 4476
 4477            this.buffer.update(cx, |buffer, cx| {
 4478                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 4479            });
 4480            for (buffer, edits) in linked_edits {
 4481                buffer.update(cx, |buffer, cx| {
 4482                    let snapshot = buffer.snapshot();
 4483                    let edits = edits
 4484                        .into_iter()
 4485                        .map(|(range, text)| {
 4486                            use text::ToPoint as TP;
 4487                            let end_point = TP::to_point(&range.end, &snapshot);
 4488                            let start_point = TP::to_point(&range.start, &snapshot);
 4489                            (start_point..end_point, text)
 4490                        })
 4491                        .sorted_by_key(|(range, _)| range.start);
 4492                    buffer.edit(edits, None, cx);
 4493                })
 4494            }
 4495            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 4496            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 4497            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 4498            let new_selections =
 4499                resolve_selections_wrapping_blocks::<usize, _>(new_anchor_selections, &map)
 4500                    .zip(new_selection_deltas)
 4501                    .map(|(selection, delta)| Selection {
 4502                        id: selection.id,
 4503                        start: selection.start + delta,
 4504                        end: selection.end + delta,
 4505                        reversed: selection.reversed,
 4506                        goal: SelectionGoal::None,
 4507                    })
 4508                    .collect::<Vec<_>>();
 4509
 4510            let mut i = 0;
 4511            for (position, delta, selection_id, pair) in new_autoclose_regions {
 4512                let position = position.to_offset(map.buffer_snapshot()) + delta;
 4513                let start = map.buffer_snapshot().anchor_before(position);
 4514                let end = map.buffer_snapshot().anchor_after(position);
 4515                while let Some(existing_state) = this.autoclose_regions.get(i) {
 4516                    match existing_state
 4517                        .range
 4518                        .start
 4519                        .cmp(&start, map.buffer_snapshot())
 4520                    {
 4521                        Ordering::Less => i += 1,
 4522                        Ordering::Greater => break,
 4523                        Ordering::Equal => {
 4524                            match end.cmp(&existing_state.range.end, map.buffer_snapshot()) {
 4525                                Ordering::Less => i += 1,
 4526                                Ordering::Equal => break,
 4527                                Ordering::Greater => break,
 4528                            }
 4529                        }
 4530                    }
 4531                }
 4532                this.autoclose_regions.insert(
 4533                    i,
 4534                    AutocloseRegion {
 4535                        selection_id,
 4536                        range: start..end,
 4537                        pair,
 4538                    },
 4539                );
 4540            }
 4541
 4542            let had_active_edit_prediction = this.has_active_edit_prediction();
 4543            this.change_selections(
 4544                SelectionEffects::scroll(Autoscroll::fit()).completions(false),
 4545                window,
 4546                cx,
 4547                |s| s.select(new_selections),
 4548            );
 4549
 4550            if !bracket_inserted
 4551                && let Some(on_type_format_task) =
 4552                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 4553            {
 4554                on_type_format_task.detach_and_log_err(cx);
 4555            }
 4556
 4557            let editor_settings = EditorSettings::get_global(cx);
 4558            if bracket_inserted
 4559                && (editor_settings.auto_signature_help
 4560                    || editor_settings.show_signature_help_after_edits)
 4561            {
 4562                this.show_signature_help(&ShowSignatureHelp, window, cx);
 4563            }
 4564
 4565            let trigger_in_words =
 4566                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
 4567            if this.hard_wrap.is_some() {
 4568                let latest: Range<Point> = this.selections.newest(&map).range();
 4569                if latest.is_empty()
 4570                    && this
 4571                        .buffer()
 4572                        .read(cx)
 4573                        .snapshot(cx)
 4574                        .line_len(MultiBufferRow(latest.start.row))
 4575                        == latest.start.column
 4576                {
 4577                    this.rewrap_impl(
 4578                        RewrapOptions {
 4579                            override_language_settings: true,
 4580                            preserve_existing_whitespace: true,
 4581                        },
 4582                        cx,
 4583                    )
 4584                }
 4585            }
 4586            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4587            refresh_linked_ranges(this, window, cx);
 4588            this.refresh_edit_prediction(true, false, window, cx);
 4589            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4590        });
 4591    }
 4592
 4593    fn find_possible_emoji_shortcode_at_position(
 4594        snapshot: &MultiBufferSnapshot,
 4595        position: Point,
 4596    ) -> Option<String> {
 4597        let mut chars = Vec::new();
 4598        let mut found_colon = false;
 4599        for char in snapshot.reversed_chars_at(position).take(100) {
 4600            // Found a possible emoji shortcode in the middle of the buffer
 4601            if found_colon {
 4602                if char.is_whitespace() {
 4603                    chars.reverse();
 4604                    return Some(chars.iter().collect());
 4605                }
 4606                // If the previous character is not a whitespace, we are in the middle of a word
 4607                // and we only want to complete the shortcode if the word is made up of other emojis
 4608                let mut containing_word = String::new();
 4609                for ch in snapshot
 4610                    .reversed_chars_at(position)
 4611                    .skip(chars.len() + 1)
 4612                    .take(100)
 4613                {
 4614                    if ch.is_whitespace() {
 4615                        break;
 4616                    }
 4617                    containing_word.push(ch);
 4618                }
 4619                let containing_word = containing_word.chars().rev().collect::<String>();
 4620                if util::word_consists_of_emojis(containing_word.as_str()) {
 4621                    chars.reverse();
 4622                    return Some(chars.iter().collect());
 4623                }
 4624            }
 4625
 4626            if char.is_whitespace() || !char.is_ascii() {
 4627                return None;
 4628            }
 4629            if char == ':' {
 4630                found_colon = true;
 4631            } else {
 4632                chars.push(char);
 4633            }
 4634        }
 4635        // Found a possible emoji shortcode at the beginning of the buffer
 4636        chars.reverse();
 4637        Some(chars.iter().collect())
 4638    }
 4639
 4640    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4641        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4642        self.transact(window, cx, |this, window, cx| {
 4643            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4644                let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
 4645                let multi_buffer = this.buffer.read(cx);
 4646                let buffer = multi_buffer.snapshot(cx);
 4647                selections
 4648                    .iter()
 4649                    .map(|selection| {
 4650                        let start_point = selection.start.to_point(&buffer);
 4651                        let mut existing_indent =
 4652                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4653                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4654                        let start = selection.start;
 4655                        let end = selection.end;
 4656                        let selection_is_empty = start == end;
 4657                        let language_scope = buffer.language_scope_at(start);
 4658                        let (
 4659                            comment_delimiter,
 4660                            doc_delimiter,
 4661                            insert_extra_newline,
 4662                            indent_on_newline,
 4663                            indent_on_extra_newline,
 4664                        ) = if let Some(language) = &language_scope {
 4665                            let mut insert_extra_newline =
 4666                                insert_extra_newline_brackets(&buffer, start..end, language)
 4667                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 4668
 4669                            // Comment extension on newline is allowed only for cursor selections
 4670                            let comment_delimiter = maybe!({
 4671                                if !selection_is_empty {
 4672                                    return None;
 4673                                }
 4674
 4675                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4676                                    return None;
 4677                                }
 4678
 4679                                let delimiters = language.line_comment_prefixes();
 4680                                let max_len_of_delimiter =
 4681                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 4682                                let (snapshot, range) =
 4683                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4684
 4685                                let num_of_whitespaces = snapshot
 4686                                    .chars_for_range(range.clone())
 4687                                    .take_while(|c| c.is_whitespace())
 4688                                    .count();
 4689                                let comment_candidate = snapshot
 4690                                    .chars_for_range(range.clone())
 4691                                    .skip(num_of_whitespaces)
 4692                                    .take(max_len_of_delimiter)
 4693                                    .collect::<String>();
 4694                                let (delimiter, trimmed_len) = delimiters
 4695                                    .iter()
 4696                                    .filter_map(|delimiter| {
 4697                                        let prefix = delimiter.trim_end();
 4698                                        if comment_candidate.starts_with(prefix) {
 4699                                            Some((delimiter, prefix.len()))
 4700                                        } else {
 4701                                            None
 4702                                        }
 4703                                    })
 4704                                    .max_by_key(|(_, len)| *len)?;
 4705
 4706                                if let Some(BlockCommentConfig {
 4707                                    start: block_start, ..
 4708                                }) = language.block_comment()
 4709                                {
 4710                                    let block_start_trimmed = block_start.trim_end();
 4711                                    if block_start_trimmed.starts_with(delimiter.trim_end()) {
 4712                                        let line_content = snapshot
 4713                                            .chars_for_range(range)
 4714                                            .skip(num_of_whitespaces)
 4715                                            .take(block_start_trimmed.len())
 4716                                            .collect::<String>();
 4717
 4718                                        if line_content.starts_with(block_start_trimmed) {
 4719                                            return None;
 4720                                        }
 4721                                    }
 4722                                }
 4723
 4724                                let cursor_is_placed_after_comment_marker =
 4725                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 4726                                if cursor_is_placed_after_comment_marker {
 4727                                    Some(delimiter.clone())
 4728                                } else {
 4729                                    None
 4730                                }
 4731                            });
 4732
 4733                            let mut indent_on_newline = IndentSize::spaces(0);
 4734                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 4735
 4736                            let doc_delimiter = maybe!({
 4737                                if !selection_is_empty {
 4738                                    return None;
 4739                                }
 4740
 4741                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4742                                    return None;
 4743                                }
 4744
 4745                                let BlockCommentConfig {
 4746                                    start: start_tag,
 4747                                    end: end_tag,
 4748                                    prefix: delimiter,
 4749                                    tab_size: len,
 4750                                } = language.documentation_comment()?;
 4751                                let is_within_block_comment = buffer
 4752                                    .language_scope_at(start_point)
 4753                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4754                                if !is_within_block_comment {
 4755                                    return None;
 4756                                }
 4757
 4758                                let (snapshot, range) =
 4759                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4760
 4761                                let num_of_whitespaces = snapshot
 4762                                    .chars_for_range(range.clone())
 4763                                    .take_while(|c| c.is_whitespace())
 4764                                    .count();
 4765
 4766                                // 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.
 4767                                let column = start_point.column;
 4768                                let cursor_is_after_start_tag = {
 4769                                    let start_tag_len = start_tag.len();
 4770                                    let start_tag_line = snapshot
 4771                                        .chars_for_range(range.clone())
 4772                                        .skip(num_of_whitespaces)
 4773                                        .take(start_tag_len)
 4774                                        .collect::<String>();
 4775                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4776                                        num_of_whitespaces + start_tag_len <= column as usize
 4777                                    } else {
 4778                                        false
 4779                                    }
 4780                                };
 4781
 4782                                let cursor_is_after_delimiter = {
 4783                                    let delimiter_trim = delimiter.trim_end();
 4784                                    let delimiter_line = snapshot
 4785                                        .chars_for_range(range.clone())
 4786                                        .skip(num_of_whitespaces)
 4787                                        .take(delimiter_trim.len())
 4788                                        .collect::<String>();
 4789                                    if delimiter_line.starts_with(delimiter_trim) {
 4790                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4791                                    } else {
 4792                                        false
 4793                                    }
 4794                                };
 4795
 4796                                let cursor_is_before_end_tag_if_exists = {
 4797                                    let mut char_position = 0u32;
 4798                                    let mut end_tag_offset = None;
 4799
 4800                                    'outer: for chunk in snapshot.text_for_range(range) {
 4801                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4802                                            let chars_before_match =
 4803                                                chunk[..byte_pos].chars().count() as u32;
 4804                                            end_tag_offset =
 4805                                                Some(char_position + chars_before_match);
 4806                                            break 'outer;
 4807                                        }
 4808                                        char_position += chunk.chars().count() as u32;
 4809                                    }
 4810
 4811                                    if let Some(end_tag_offset) = end_tag_offset {
 4812                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4813                                        if cursor_is_after_start_tag {
 4814                                            if cursor_is_before_end_tag {
 4815                                                insert_extra_newline = true;
 4816                                            }
 4817                                            let cursor_is_at_start_of_end_tag =
 4818                                                column == end_tag_offset;
 4819                                            if cursor_is_at_start_of_end_tag {
 4820                                                indent_on_extra_newline.len = *len;
 4821                                            }
 4822                                        }
 4823                                        cursor_is_before_end_tag
 4824                                    } else {
 4825                                        true
 4826                                    }
 4827                                };
 4828
 4829                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4830                                    && cursor_is_before_end_tag_if_exists
 4831                                {
 4832                                    if cursor_is_after_start_tag {
 4833                                        indent_on_newline.len = *len;
 4834                                    }
 4835                                    Some(delimiter.clone())
 4836                                } else {
 4837                                    None
 4838                                }
 4839                            });
 4840
 4841                            (
 4842                                comment_delimiter,
 4843                                doc_delimiter,
 4844                                insert_extra_newline,
 4845                                indent_on_newline,
 4846                                indent_on_extra_newline,
 4847                            )
 4848                        } else {
 4849                            (
 4850                                None,
 4851                                None,
 4852                                false,
 4853                                IndentSize::default(),
 4854                                IndentSize::default(),
 4855                            )
 4856                        };
 4857
 4858                        let prevent_auto_indent = doc_delimiter.is_some();
 4859                        let delimiter = comment_delimiter.or(doc_delimiter);
 4860
 4861                        let capacity_for_delimiter =
 4862                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4863                        let mut new_text = String::with_capacity(
 4864                            1 + capacity_for_delimiter
 4865                                + existing_indent.len as usize
 4866                                + indent_on_newline.len as usize
 4867                                + indent_on_extra_newline.len as usize,
 4868                        );
 4869                        new_text.push('\n');
 4870                        new_text.extend(existing_indent.chars());
 4871                        new_text.extend(indent_on_newline.chars());
 4872
 4873                        if let Some(delimiter) = &delimiter {
 4874                            new_text.push_str(delimiter);
 4875                        }
 4876
 4877                        if insert_extra_newline {
 4878                            new_text.push('\n');
 4879                            new_text.extend(existing_indent.chars());
 4880                            new_text.extend(indent_on_extra_newline.chars());
 4881                        }
 4882
 4883                        let anchor = buffer.anchor_after(end);
 4884                        let new_selection = selection.map(|_| anchor);
 4885                        (
 4886                            ((start..end, new_text), prevent_auto_indent),
 4887                            (insert_extra_newline, new_selection),
 4888                        )
 4889                    })
 4890                    .unzip()
 4891            };
 4892
 4893            let mut auto_indent_edits = Vec::new();
 4894            let mut edits = Vec::new();
 4895            for (edit, prevent_auto_indent) in edits_with_flags {
 4896                if prevent_auto_indent {
 4897                    edits.push(edit);
 4898                } else {
 4899                    auto_indent_edits.push(edit);
 4900                }
 4901            }
 4902            if !edits.is_empty() {
 4903                this.edit(edits, cx);
 4904            }
 4905            if !auto_indent_edits.is_empty() {
 4906                this.edit_with_autoindent(auto_indent_edits, cx);
 4907            }
 4908
 4909            let buffer = this.buffer.read(cx).snapshot(cx);
 4910            let new_selections = selection_info
 4911                .into_iter()
 4912                .map(|(extra_newline_inserted, new_selection)| {
 4913                    let mut cursor = new_selection.end.to_point(&buffer);
 4914                    if extra_newline_inserted {
 4915                        cursor.row -= 1;
 4916                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4917                    }
 4918                    new_selection.map(|_| cursor)
 4919                })
 4920                .collect();
 4921
 4922            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
 4923            this.refresh_edit_prediction(true, false, window, cx);
 4924        });
 4925    }
 4926
 4927    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4928        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4929
 4930        let buffer = self.buffer.read(cx);
 4931        let snapshot = buffer.snapshot(cx);
 4932
 4933        let mut edits = Vec::new();
 4934        let mut rows = Vec::new();
 4935
 4936        for (rows_inserted, selection) in self
 4937            .selections
 4938            .all_adjusted(&self.display_snapshot(cx))
 4939            .into_iter()
 4940            .enumerate()
 4941        {
 4942            let cursor = selection.head();
 4943            let row = cursor.row;
 4944
 4945            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4946
 4947            let newline = "\n".to_string();
 4948            edits.push((start_of_line..start_of_line, newline));
 4949
 4950            rows.push(row + rows_inserted as u32);
 4951        }
 4952
 4953        self.transact(window, cx, |editor, window, cx| {
 4954            editor.edit(edits, cx);
 4955
 4956            editor.change_selections(Default::default(), window, cx, |s| {
 4957                let mut index = 0;
 4958                s.move_cursors_with(|map, _, _| {
 4959                    let row = rows[index];
 4960                    index += 1;
 4961
 4962                    let point = Point::new(row, 0);
 4963                    let boundary = map.next_line_boundary(point).1;
 4964                    let clipped = map.clip_point(boundary, Bias::Left);
 4965
 4966                    (clipped, SelectionGoal::None)
 4967                });
 4968            });
 4969
 4970            let mut indent_edits = Vec::new();
 4971            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4972            for row in rows {
 4973                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4974                for (row, indent) in indents {
 4975                    if indent.len == 0 {
 4976                        continue;
 4977                    }
 4978
 4979                    let text = match indent.kind {
 4980                        IndentKind::Space => " ".repeat(indent.len as usize),
 4981                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4982                    };
 4983                    let point = Point::new(row.0, 0);
 4984                    indent_edits.push((point..point, text));
 4985                }
 4986            }
 4987            editor.edit(indent_edits, cx);
 4988        });
 4989    }
 4990
 4991    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 4992        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4993
 4994        let buffer = self.buffer.read(cx);
 4995        let snapshot = buffer.snapshot(cx);
 4996
 4997        let mut edits = Vec::new();
 4998        let mut rows = Vec::new();
 4999        let mut rows_inserted = 0;
 5000
 5001        for selection in self.selections.all_adjusted(&self.display_snapshot(cx)) {
 5002            let cursor = selection.head();
 5003            let row = cursor.row;
 5004
 5005            let point = Point::new(row + 1, 0);
 5006            let start_of_line = snapshot.clip_point(point, Bias::Left);
 5007
 5008            let newline = "\n".to_string();
 5009            edits.push((start_of_line..start_of_line, newline));
 5010
 5011            rows_inserted += 1;
 5012            rows.push(row + rows_inserted);
 5013        }
 5014
 5015        self.transact(window, cx, |editor, window, cx| {
 5016            editor.edit(edits, cx);
 5017
 5018            editor.change_selections(Default::default(), window, cx, |s| {
 5019                let mut index = 0;
 5020                s.move_cursors_with(|map, _, _| {
 5021                    let row = rows[index];
 5022                    index += 1;
 5023
 5024                    let point = Point::new(row, 0);
 5025                    let boundary = map.next_line_boundary(point).1;
 5026                    let clipped = map.clip_point(boundary, Bias::Left);
 5027
 5028                    (clipped, SelectionGoal::None)
 5029                });
 5030            });
 5031
 5032            let mut indent_edits = Vec::new();
 5033            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 5034            for row in rows {
 5035                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 5036                for (row, indent) in indents {
 5037                    if indent.len == 0 {
 5038                        continue;
 5039                    }
 5040
 5041                    let text = match indent.kind {
 5042                        IndentKind::Space => " ".repeat(indent.len as usize),
 5043                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 5044                    };
 5045                    let point = Point::new(row.0, 0);
 5046                    indent_edits.push((point..point, text));
 5047                }
 5048            }
 5049            editor.edit(indent_edits, cx);
 5050        });
 5051    }
 5052
 5053    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 5054        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 5055            original_indent_columns: Vec::new(),
 5056        });
 5057        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 5058    }
 5059
 5060    fn insert_with_autoindent_mode(
 5061        &mut self,
 5062        text: &str,
 5063        autoindent_mode: Option<AutoindentMode>,
 5064        window: &mut Window,
 5065        cx: &mut Context<Self>,
 5066    ) {
 5067        if self.read_only(cx) {
 5068            return;
 5069        }
 5070
 5071        let text: Arc<str> = text.into();
 5072        self.transact(window, cx, |this, window, cx| {
 5073            let old_selections = this.selections.all_adjusted(&this.display_snapshot(cx));
 5074            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 5075                let anchors = {
 5076                    let snapshot = buffer.read(cx);
 5077                    old_selections
 5078                        .iter()
 5079                        .map(|s| {
 5080                            let anchor = snapshot.anchor_after(s.head());
 5081                            s.map(|_| anchor)
 5082                        })
 5083                        .collect::<Vec<_>>()
 5084                };
 5085                buffer.edit(
 5086                    old_selections
 5087                        .iter()
 5088                        .map(|s| (s.start..s.end, text.clone())),
 5089                    autoindent_mode,
 5090                    cx,
 5091                );
 5092                anchors
 5093            });
 5094
 5095            this.change_selections(Default::default(), window, cx, |s| {
 5096                s.select_anchors(selection_anchors);
 5097            });
 5098
 5099            cx.notify();
 5100        });
 5101    }
 5102
 5103    fn trigger_completion_on_input(
 5104        &mut self,
 5105        text: &str,
 5106        trigger_in_words: bool,
 5107        window: &mut Window,
 5108        cx: &mut Context<Self>,
 5109    ) {
 5110        let completions_source = self
 5111            .context_menu
 5112            .borrow()
 5113            .as_ref()
 5114            .and_then(|menu| match menu {
 5115                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 5116                CodeContextMenu::CodeActions(_) => None,
 5117            });
 5118
 5119        match completions_source {
 5120            Some(CompletionsMenuSource::Words { .. }) => {
 5121                self.open_or_update_completions_menu(
 5122                    Some(CompletionsMenuSource::Words {
 5123                        ignore_threshold: false,
 5124                    }),
 5125                    None,
 5126                    trigger_in_words,
 5127                    window,
 5128                    cx,
 5129                );
 5130            }
 5131            _ => self.open_or_update_completions_menu(
 5132                None,
 5133                Some(text.to_owned()).filter(|x| !x.is_empty()),
 5134                true,
 5135                window,
 5136                cx,
 5137            ),
 5138        }
 5139    }
 5140
 5141    /// If any empty selections is touching the start of its innermost containing autoclose
 5142    /// region, expand it to select the brackets.
 5143    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 5144        let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
 5145        let buffer = self.buffer.read(cx).read(cx);
 5146        let new_selections = self
 5147            .selections_with_autoclose_regions(selections, &buffer)
 5148            .map(|(mut selection, region)| {
 5149                if !selection.is_empty() {
 5150                    return selection;
 5151                }
 5152
 5153                if let Some(region) = region {
 5154                    let mut range = region.range.to_offset(&buffer);
 5155                    if selection.start == range.start && range.start >= region.pair.start.len() {
 5156                        range.start -= region.pair.start.len();
 5157                        if buffer.contains_str_at(range.start, &region.pair.start)
 5158                            && buffer.contains_str_at(range.end, &region.pair.end)
 5159                        {
 5160                            range.end += region.pair.end.len();
 5161                            selection.start = range.start;
 5162                            selection.end = range.end;
 5163
 5164                            return selection;
 5165                        }
 5166                    }
 5167                }
 5168
 5169                let always_treat_brackets_as_autoclosed = buffer
 5170                    .language_settings_at(selection.start, cx)
 5171                    .always_treat_brackets_as_autoclosed;
 5172
 5173                if !always_treat_brackets_as_autoclosed {
 5174                    return selection;
 5175                }
 5176
 5177                if let Some(scope) = buffer.language_scope_at(selection.start) {
 5178                    for (pair, enabled) in scope.brackets() {
 5179                        if !enabled || !pair.close {
 5180                            continue;
 5181                        }
 5182
 5183                        if buffer.contains_str_at(selection.start, &pair.end) {
 5184                            let pair_start_len = pair.start.len();
 5185                            if buffer.contains_str_at(
 5186                                selection.start.saturating_sub(pair_start_len),
 5187                                &pair.start,
 5188                            ) {
 5189                                selection.start -= pair_start_len;
 5190                                selection.end += pair.end.len();
 5191
 5192                                return selection;
 5193                            }
 5194                        }
 5195                    }
 5196                }
 5197
 5198                selection
 5199            })
 5200            .collect();
 5201
 5202        drop(buffer);
 5203        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
 5204            selections.select(new_selections)
 5205        });
 5206    }
 5207
 5208    /// Iterate the given selections, and for each one, find the smallest surrounding
 5209    /// autoclose region. This uses the ordering of the selections and the autoclose
 5210    /// regions to avoid repeated comparisons.
 5211    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 5212        &'a self,
 5213        selections: impl IntoIterator<Item = Selection<D>>,
 5214        buffer: &'a MultiBufferSnapshot,
 5215    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 5216        let mut i = 0;
 5217        let mut regions = self.autoclose_regions.as_slice();
 5218        selections.into_iter().map(move |selection| {
 5219            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 5220
 5221            let mut enclosing = None;
 5222            while let Some(pair_state) = regions.get(i) {
 5223                if pair_state.range.end.to_offset(buffer) < range.start {
 5224                    regions = &regions[i + 1..];
 5225                    i = 0;
 5226                } else if pair_state.range.start.to_offset(buffer) > range.end {
 5227                    break;
 5228                } else {
 5229                    if pair_state.selection_id == selection.id {
 5230                        enclosing = Some(pair_state);
 5231                    }
 5232                    i += 1;
 5233                }
 5234            }
 5235
 5236            (selection, enclosing)
 5237        })
 5238    }
 5239
 5240    /// Remove any autoclose regions that no longer contain their selection or have invalid anchors in ranges.
 5241    fn invalidate_autoclose_regions(
 5242        &mut self,
 5243        mut selections: &[Selection<Anchor>],
 5244        buffer: &MultiBufferSnapshot,
 5245    ) {
 5246        self.autoclose_regions.retain(|state| {
 5247            if !state.range.start.is_valid(buffer) || !state.range.end.is_valid(buffer) {
 5248                return false;
 5249            }
 5250
 5251            let mut i = 0;
 5252            while let Some(selection) = selections.get(i) {
 5253                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 5254                    selections = &selections[1..];
 5255                    continue;
 5256                }
 5257                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 5258                    break;
 5259                }
 5260                if selection.id == state.selection_id {
 5261                    return true;
 5262                } else {
 5263                    i += 1;
 5264                }
 5265            }
 5266            false
 5267        });
 5268    }
 5269
 5270    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 5271        let offset = position.to_offset(buffer);
 5272        let (word_range, kind) =
 5273            buffer.surrounding_word(offset, Some(CharScopeContext::Completion));
 5274        if offset > word_range.start && kind == Some(CharKind::Word) {
 5275            Some(
 5276                buffer
 5277                    .text_for_range(word_range.start..offset)
 5278                    .collect::<String>(),
 5279            )
 5280        } else {
 5281            None
 5282        }
 5283    }
 5284
 5285    pub fn visible_excerpts(
 5286        &self,
 5287        cx: &mut Context<Editor>,
 5288    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 5289        let Some(project) = self.project() else {
 5290            return HashMap::default();
 5291        };
 5292        let project = project.read(cx);
 5293        let multi_buffer = self.buffer().read(cx);
 5294        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 5295        let multi_buffer_visible_start = self
 5296            .scroll_manager
 5297            .anchor()
 5298            .anchor
 5299            .to_point(&multi_buffer_snapshot);
 5300        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 5301            multi_buffer_visible_start
 5302                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 5303            Bias::Left,
 5304        );
 5305        multi_buffer_snapshot
 5306            .range_to_buffer_ranges(multi_buffer_visible_start..multi_buffer_visible_end)
 5307            .into_iter()
 5308            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 5309            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 5310                let buffer_file = project::File::from_dyn(buffer.file())?;
 5311                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 5312                let worktree_entry = buffer_worktree
 5313                    .read(cx)
 5314                    .entry_for_id(buffer_file.project_entry_id()?)?;
 5315                if worktree_entry.is_ignored {
 5316                    None
 5317                } else {
 5318                    Some((
 5319                        excerpt_id,
 5320                        (
 5321                            multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5322                            buffer.version().clone(),
 5323                            excerpt_visible_range,
 5324                        ),
 5325                    ))
 5326                }
 5327            })
 5328            .collect()
 5329    }
 5330
 5331    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 5332        TextLayoutDetails {
 5333            text_system: window.text_system().clone(),
 5334            editor_style: self.style.clone().unwrap(),
 5335            rem_size: window.rem_size(),
 5336            scroll_anchor: self.scroll_manager.anchor(),
 5337            visible_rows: self.visible_line_count(),
 5338            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 5339        }
 5340    }
 5341
 5342    fn trigger_on_type_formatting(
 5343        &self,
 5344        input: String,
 5345        window: &mut Window,
 5346        cx: &mut Context<Self>,
 5347    ) -> Option<Task<Result<()>>> {
 5348        if input.len() != 1 {
 5349            return None;
 5350        }
 5351
 5352        let project = self.project()?;
 5353        let position = self.selections.newest_anchor().head();
 5354        let (buffer, buffer_position) = self
 5355            .buffer
 5356            .read(cx)
 5357            .text_anchor_for_position(position, cx)?;
 5358
 5359        let settings = language_settings::language_settings(
 5360            buffer
 5361                .read(cx)
 5362                .language_at(buffer_position)
 5363                .map(|l| l.name()),
 5364            buffer.read(cx).file(),
 5365            cx,
 5366        );
 5367        if !settings.use_on_type_format {
 5368            return None;
 5369        }
 5370
 5371        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5372        // hence we do LSP request & edit on host side only — add formats to host's history.
 5373        let push_to_lsp_host_history = true;
 5374        // If this is not the host, append its history with new edits.
 5375        let push_to_client_history = project.read(cx).is_via_collab();
 5376
 5377        let on_type_formatting = project.update(cx, |project, cx| {
 5378            project.on_type_format(
 5379                buffer.clone(),
 5380                buffer_position,
 5381                input,
 5382                push_to_lsp_host_history,
 5383                cx,
 5384            )
 5385        });
 5386        Some(cx.spawn_in(window, async move |editor, cx| {
 5387            if let Some(transaction) = on_type_formatting.await? {
 5388                if push_to_client_history {
 5389                    buffer
 5390                        .update(cx, |buffer, _| {
 5391                            buffer.push_transaction(transaction, Instant::now());
 5392                            buffer.finalize_last_transaction();
 5393                        })
 5394                        .ok();
 5395                }
 5396                editor.update(cx, |editor, cx| {
 5397                    editor.refresh_document_highlights(cx);
 5398                })?;
 5399            }
 5400            Ok(())
 5401        }))
 5402    }
 5403
 5404    pub fn show_word_completions(
 5405        &mut self,
 5406        _: &ShowWordCompletions,
 5407        window: &mut Window,
 5408        cx: &mut Context<Self>,
 5409    ) {
 5410        self.open_or_update_completions_menu(
 5411            Some(CompletionsMenuSource::Words {
 5412                ignore_threshold: true,
 5413            }),
 5414            None,
 5415            false,
 5416            window,
 5417            cx,
 5418        );
 5419    }
 5420
 5421    pub fn show_completions(
 5422        &mut self,
 5423        _: &ShowCompletions,
 5424        window: &mut Window,
 5425        cx: &mut Context<Self>,
 5426    ) {
 5427        self.open_or_update_completions_menu(None, None, false, window, cx);
 5428    }
 5429
 5430    fn open_or_update_completions_menu(
 5431        &mut self,
 5432        requested_source: Option<CompletionsMenuSource>,
 5433        trigger: Option<String>,
 5434        trigger_in_words: bool,
 5435        window: &mut Window,
 5436        cx: &mut Context<Self>,
 5437    ) {
 5438        if self.pending_rename.is_some() {
 5439            return;
 5440        }
 5441
 5442        let completions_source = self
 5443            .context_menu
 5444            .borrow()
 5445            .as_ref()
 5446            .and_then(|menu| match menu {
 5447                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 5448                CodeContextMenu::CodeActions(_) => None,
 5449            });
 5450
 5451        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5452
 5453        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5454        // inserted and selected. To handle that case, the start of the selection is used so that
 5455        // the menu starts with all choices.
 5456        let position = self
 5457            .selections
 5458            .newest_anchor()
 5459            .start
 5460            .bias_right(&multibuffer_snapshot);
 5461        if position.diff_base_anchor.is_some() {
 5462            return;
 5463        }
 5464        let buffer_position = multibuffer_snapshot.anchor_before(position);
 5465        let Some(buffer) = buffer_position
 5466            .buffer_id
 5467            .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
 5468        else {
 5469            return;
 5470        };
 5471        let buffer_snapshot = buffer.read(cx).snapshot();
 5472
 5473        let query: Option<Arc<String>> =
 5474            Self::completion_query(&multibuffer_snapshot, buffer_position)
 5475                .map(|query| query.into());
 5476
 5477        drop(multibuffer_snapshot);
 5478
 5479        // Hide the current completions menu when query is empty. Without this, cached
 5480        // completions from before the trigger char may be reused (#32774).
 5481        if query.is_none() {
 5482            let menu_is_open = matches!(
 5483                self.context_menu.borrow().as_ref(),
 5484                Some(CodeContextMenu::Completions(_))
 5485            );
 5486            if menu_is_open {
 5487                self.hide_context_menu(window, cx);
 5488            }
 5489        }
 5490
 5491        let mut ignore_word_threshold = false;
 5492        let provider = match requested_source {
 5493            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5494            Some(CompletionsMenuSource::Words { ignore_threshold }) => {
 5495                ignore_word_threshold = ignore_threshold;
 5496                None
 5497            }
 5498            Some(CompletionsMenuSource::SnippetChoices)
 5499            | Some(CompletionsMenuSource::SnippetsOnly) => {
 5500                log::error!("bug: SnippetChoices requested_source is not handled");
 5501                None
 5502            }
 5503        };
 5504
 5505        let sort_completions = provider
 5506            .as_ref()
 5507            .is_some_and(|provider| provider.sort_completions());
 5508
 5509        let filter_completions = provider
 5510            .as_ref()
 5511            .is_none_or(|provider| provider.filter_completions());
 5512
 5513        let was_snippets_only = matches!(
 5514            completions_source,
 5515            Some(CompletionsMenuSource::SnippetsOnly)
 5516        );
 5517
 5518        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5519            if filter_completions {
 5520                menu.filter(query.clone(), provider.clone(), window, cx);
 5521            }
 5522            // When `is_incomplete` is false, no need to re-query completions when the current query
 5523            // is a suffix of the initial query.
 5524            let was_complete = !menu.is_incomplete;
 5525            if was_complete && !was_snippets_only {
 5526                // If the new query is a suffix of the old query (typing more characters) and
 5527                // the previous result was complete, the existing completions can be filtered.
 5528                //
 5529                // Note that this is always true for snippet completions.
 5530                let query_matches = match (&menu.initial_query, &query) {
 5531                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5532                    (None, _) => true,
 5533                    _ => false,
 5534                };
 5535                if query_matches {
 5536                    let position_matches = if menu.initial_position == position {
 5537                        true
 5538                    } else {
 5539                        let snapshot = self.buffer.read(cx).read(cx);
 5540                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5541                    };
 5542                    if position_matches {
 5543                        return;
 5544                    }
 5545                }
 5546            }
 5547        };
 5548
 5549        let Anchor {
 5550            excerpt_id: buffer_excerpt_id,
 5551            text_anchor: buffer_position,
 5552            ..
 5553        } = buffer_position;
 5554
 5555        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5556            buffer_snapshot.surrounding_word(buffer_position, None)
 5557        {
 5558            let word_to_exclude = buffer_snapshot
 5559                .text_for_range(word_range.clone())
 5560                .collect::<String>();
 5561            (
 5562                buffer_snapshot.anchor_before(word_range.start)
 5563                    ..buffer_snapshot.anchor_after(buffer_position),
 5564                Some(word_to_exclude),
 5565            )
 5566        } else {
 5567            (buffer_position..buffer_position, None)
 5568        };
 5569
 5570        let language = buffer_snapshot
 5571            .language_at(buffer_position)
 5572            .map(|language| language.name());
 5573
 5574        let completion_settings = language_settings(language.clone(), buffer_snapshot.file(), cx)
 5575            .completions
 5576            .clone();
 5577
 5578        let show_completion_documentation = buffer_snapshot
 5579            .settings_at(buffer_position, cx)
 5580            .show_completion_documentation;
 5581
 5582        // The document can be large, so stay in reasonable bounds when searching for words,
 5583        // otherwise completion pop-up might be slow to appear.
 5584        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5585        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5586        let min_word_search = buffer_snapshot.clip_point(
 5587            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5588            Bias::Left,
 5589        );
 5590        let max_word_search = buffer_snapshot.clip_point(
 5591            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5592            Bias::Right,
 5593        );
 5594        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5595            ..buffer_snapshot.point_to_offset(max_word_search);
 5596
 5597        let skip_digits = query
 5598            .as_ref()
 5599            .is_none_or(|query| !query.chars().any(|c| c.is_digit(10)));
 5600
 5601        let load_provider_completions = provider.as_ref().is_some_and(|provider| {
 5602            trigger.as_ref().is_none_or(|trigger| {
 5603                provider.is_completion_trigger(
 5604                    &buffer,
 5605                    position.text_anchor,
 5606                    trigger,
 5607                    trigger_in_words,
 5608                    completions_source.is_some(),
 5609                    cx,
 5610                )
 5611            })
 5612        });
 5613
 5614        let provider_responses = if let Some(provider) = &provider
 5615            && load_provider_completions
 5616        {
 5617            let trigger_character =
 5618                trigger.filter(|trigger| buffer.read(cx).completion_triggers().contains(trigger));
 5619            let completion_context = CompletionContext {
 5620                trigger_kind: match &trigger_character {
 5621                    Some(_) => CompletionTriggerKind::TRIGGER_CHARACTER,
 5622                    None => CompletionTriggerKind::INVOKED,
 5623                },
 5624                trigger_character,
 5625            };
 5626
 5627            provider.completions(
 5628                buffer_excerpt_id,
 5629                &buffer,
 5630                buffer_position,
 5631                completion_context,
 5632                window,
 5633                cx,
 5634            )
 5635        } else {
 5636            Task::ready(Ok(Vec::new()))
 5637        };
 5638
 5639        let load_word_completions = if !self.word_completions_enabled {
 5640            false
 5641        } else if requested_source
 5642            == Some(CompletionsMenuSource::Words {
 5643                ignore_threshold: true,
 5644            })
 5645        {
 5646            true
 5647        } else {
 5648            load_provider_completions
 5649                && completion_settings.words != WordsCompletionMode::Disabled
 5650                && (ignore_word_threshold || {
 5651                    let words_min_length = completion_settings.words_min_length;
 5652                    // check whether word has at least `words_min_length` characters
 5653                    let query_chars = query.iter().flat_map(|q| q.chars());
 5654                    query_chars.take(words_min_length).count() == words_min_length
 5655                })
 5656        };
 5657
 5658        let mut words = if load_word_completions {
 5659            cx.background_spawn(async move {
 5660                buffer_snapshot.words_in_range(WordsQuery {
 5661                    fuzzy_contents: None,
 5662                    range: word_search_range,
 5663                    skip_digits,
 5664                })
 5665            })
 5666        } else {
 5667            Task::ready(BTreeMap::default())
 5668        };
 5669
 5670        let snippets = if let Some(provider) = &provider
 5671            && provider.show_snippets()
 5672            && let Some(project) = self.project()
 5673        {
 5674            project.update(cx, |project, cx| {
 5675                snippet_completions(project, &buffer, buffer_position, cx)
 5676            })
 5677        } else {
 5678            Task::ready(Ok(CompletionResponse {
 5679                completions: Vec::new(),
 5680                display_options: Default::default(),
 5681                is_incomplete: false,
 5682            }))
 5683        };
 5684
 5685        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5686
 5687        let id = post_inc(&mut self.next_completion_id);
 5688        let task = cx.spawn_in(window, async move |editor, cx| {
 5689            let Ok(()) = editor.update(cx, |this, _| {
 5690                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5691            }) else {
 5692                return;
 5693            };
 5694
 5695            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5696            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5697            let mut completions = Vec::new();
 5698            let mut is_incomplete = false;
 5699            let mut display_options: Option<CompletionDisplayOptions> = None;
 5700            if let Some(provider_responses) = provider_responses.await.log_err()
 5701                && !provider_responses.is_empty()
 5702            {
 5703                for response in provider_responses {
 5704                    completions.extend(response.completions);
 5705                    is_incomplete = is_incomplete || response.is_incomplete;
 5706                    match display_options.as_mut() {
 5707                        None => {
 5708                            display_options = Some(response.display_options);
 5709                        }
 5710                        Some(options) => options.merge(&response.display_options),
 5711                    }
 5712                }
 5713                if completion_settings.words == WordsCompletionMode::Fallback {
 5714                    words = Task::ready(BTreeMap::default());
 5715                }
 5716            }
 5717            let display_options = display_options.unwrap_or_default();
 5718
 5719            let mut words = words.await;
 5720            if let Some(word_to_exclude) = &word_to_exclude {
 5721                words.remove(word_to_exclude);
 5722            }
 5723            for lsp_completion in &completions {
 5724                words.remove(&lsp_completion.new_text);
 5725            }
 5726            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5727                replace_range: word_replace_range.clone(),
 5728                new_text: word.clone(),
 5729                label: CodeLabel::plain(word, None),
 5730                icon_path: None,
 5731                documentation: None,
 5732                source: CompletionSource::BufferWord {
 5733                    word_range,
 5734                    resolved: false,
 5735                },
 5736                insert_text_mode: Some(InsertTextMode::AS_IS),
 5737                confirm: None,
 5738            }));
 5739
 5740            completions.extend(
 5741                snippets
 5742                    .await
 5743                    .into_iter()
 5744                    .flat_map(|response| response.completions),
 5745            );
 5746
 5747            let menu = if completions.is_empty() {
 5748                None
 5749            } else {
 5750                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5751                    let languages = editor
 5752                        .workspace
 5753                        .as_ref()
 5754                        .and_then(|(workspace, _)| workspace.upgrade())
 5755                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5756                    let menu = CompletionsMenu::new(
 5757                        id,
 5758                        requested_source.unwrap_or(if load_provider_completions {
 5759                            CompletionsMenuSource::Normal
 5760                        } else {
 5761                            CompletionsMenuSource::SnippetsOnly
 5762                        }),
 5763                        sort_completions,
 5764                        show_completion_documentation,
 5765                        position,
 5766                        query.clone(),
 5767                        is_incomplete,
 5768                        buffer.clone(),
 5769                        completions.into(),
 5770                        display_options,
 5771                        snippet_sort_order,
 5772                        languages,
 5773                        language,
 5774                        cx,
 5775                    );
 5776
 5777                    let query = if filter_completions { query } else { None };
 5778                    let matches_task = if let Some(query) = query {
 5779                        menu.do_async_filtering(query, cx)
 5780                    } else {
 5781                        Task::ready(menu.unfiltered_matches())
 5782                    };
 5783                    (menu, matches_task)
 5784                }) else {
 5785                    return;
 5786                };
 5787
 5788                let matches = matches_task.await;
 5789
 5790                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5791                    // Newer menu already set, so exit.
 5792                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5793                        editor.context_menu.borrow().as_ref()
 5794                        && prev_menu.id > id
 5795                    {
 5796                        return;
 5797                    };
 5798
 5799                    // Only valid to take prev_menu because it the new menu is immediately set
 5800                    // below, or the menu is hidden.
 5801                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5802                        editor.context_menu.borrow_mut().take()
 5803                    {
 5804                        let position_matches =
 5805                            if prev_menu.initial_position == menu.initial_position {
 5806                                true
 5807                            } else {
 5808                                let snapshot = editor.buffer.read(cx).read(cx);
 5809                                prev_menu.initial_position.to_offset(&snapshot)
 5810                                    == menu.initial_position.to_offset(&snapshot)
 5811                            };
 5812                        if position_matches {
 5813                            // Preserve markdown cache before `set_filter_results` because it will
 5814                            // try to populate the documentation cache.
 5815                            menu.preserve_markdown_cache(prev_menu);
 5816                        }
 5817                    };
 5818
 5819                    menu.set_filter_results(matches, provider, window, cx);
 5820                }) else {
 5821                    return;
 5822                };
 5823
 5824                menu.visible().then_some(menu)
 5825            };
 5826
 5827            editor
 5828                .update_in(cx, |editor, window, cx| {
 5829                    if editor.focus_handle.is_focused(window)
 5830                        && let Some(menu) = menu
 5831                    {
 5832                        *editor.context_menu.borrow_mut() =
 5833                            Some(CodeContextMenu::Completions(menu));
 5834
 5835                        crate::hover_popover::hide_hover(editor, cx);
 5836                        if editor.show_edit_predictions_in_menu() {
 5837                            editor.update_visible_edit_prediction(window, cx);
 5838                        } else {
 5839                            editor.discard_edit_prediction(false, cx);
 5840                        }
 5841
 5842                        cx.notify();
 5843                        return;
 5844                    }
 5845
 5846                    if editor.completion_tasks.len() <= 1 {
 5847                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 5848                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5849                        // If it was already hidden and we don't show edit predictions in the menu,
 5850                        // we should also show the edit prediction when available.
 5851                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5852                            editor.update_visible_edit_prediction(window, cx);
 5853                        }
 5854                    }
 5855                })
 5856                .ok();
 5857        });
 5858
 5859        self.completion_tasks.push((id, task));
 5860    }
 5861
 5862    #[cfg(feature = "test-support")]
 5863    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5864        let menu = self.context_menu.borrow();
 5865        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5866            let completions = menu.completions.borrow();
 5867            Some(completions.to_vec())
 5868        } else {
 5869            None
 5870        }
 5871    }
 5872
 5873    pub fn with_completions_menu_matching_id<R>(
 5874        &self,
 5875        id: CompletionId,
 5876        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 5877    ) -> R {
 5878        let mut context_menu = self.context_menu.borrow_mut();
 5879        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 5880            return f(None);
 5881        };
 5882        if completions_menu.id != id {
 5883            return f(None);
 5884        }
 5885        f(Some(completions_menu))
 5886    }
 5887
 5888    pub fn confirm_completion(
 5889        &mut self,
 5890        action: &ConfirmCompletion,
 5891        window: &mut Window,
 5892        cx: &mut Context<Self>,
 5893    ) -> Option<Task<Result<()>>> {
 5894        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5895        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5896    }
 5897
 5898    pub fn confirm_completion_insert(
 5899        &mut self,
 5900        _: &ConfirmCompletionInsert,
 5901        window: &mut Window,
 5902        cx: &mut Context<Self>,
 5903    ) -> Option<Task<Result<()>>> {
 5904        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5905        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5906    }
 5907
 5908    pub fn confirm_completion_replace(
 5909        &mut self,
 5910        _: &ConfirmCompletionReplace,
 5911        window: &mut Window,
 5912        cx: &mut Context<Self>,
 5913    ) -> Option<Task<Result<()>>> {
 5914        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5915        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5916    }
 5917
 5918    pub fn compose_completion(
 5919        &mut self,
 5920        action: &ComposeCompletion,
 5921        window: &mut Window,
 5922        cx: &mut Context<Self>,
 5923    ) -> Option<Task<Result<()>>> {
 5924        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5925        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5926    }
 5927
 5928    fn do_completion(
 5929        &mut self,
 5930        item_ix: Option<usize>,
 5931        intent: CompletionIntent,
 5932        window: &mut Window,
 5933        cx: &mut Context<Editor>,
 5934    ) -> Option<Task<Result<()>>> {
 5935        use language::ToOffset as _;
 5936
 5937        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5938        else {
 5939            return None;
 5940        };
 5941
 5942        let candidate_id = {
 5943            let entries = completions_menu.entries.borrow();
 5944            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5945            if self.show_edit_predictions_in_menu() {
 5946                self.discard_edit_prediction(true, cx);
 5947            }
 5948            mat.candidate_id
 5949        };
 5950
 5951        let completion = completions_menu
 5952            .completions
 5953            .borrow()
 5954            .get(candidate_id)?
 5955            .clone();
 5956        cx.stop_propagation();
 5957
 5958        let buffer_handle = completions_menu.buffer.clone();
 5959
 5960        let CompletionEdit {
 5961            new_text,
 5962            snippet,
 5963            replace_range,
 5964        } = process_completion_for_edit(
 5965            &completion,
 5966            intent,
 5967            &buffer_handle,
 5968            &completions_menu.initial_position.text_anchor,
 5969            cx,
 5970        );
 5971
 5972        let buffer = buffer_handle.read(cx);
 5973        let snapshot = self.buffer.read(cx).snapshot(cx);
 5974        let newest_anchor = self.selections.newest_anchor();
 5975        let replace_range_multibuffer = {
 5976            let mut excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 5977            excerpt.map_range_from_buffer(replace_range.clone())
 5978        };
 5979        if snapshot.buffer_id_for_anchor(newest_anchor.head()) != Some(buffer.remote_id()) {
 5980            return None;
 5981        }
 5982
 5983        let old_text = buffer
 5984            .text_for_range(replace_range.clone())
 5985            .collect::<String>();
 5986        let lookbehind = newest_anchor
 5987            .start
 5988            .text_anchor
 5989            .to_offset(buffer)
 5990            .saturating_sub(replace_range.start);
 5991        let lookahead = replace_range
 5992            .end
 5993            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 5994        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 5995        let suffix = &old_text[lookbehind.min(old_text.len())..];
 5996
 5997        let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
 5998        let mut ranges = Vec::new();
 5999        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 6000
 6001        for selection in &selections {
 6002            let range = if selection.id == newest_anchor.id {
 6003                replace_range_multibuffer.clone()
 6004            } else {
 6005                let mut range = selection.range();
 6006
 6007                // if prefix is present, don't duplicate it
 6008                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 6009                    range.start = range.start.saturating_sub(lookbehind);
 6010
 6011                    // if suffix is also present, mimic the newest cursor and replace it
 6012                    if selection.id != newest_anchor.id
 6013                        && snapshot.contains_str_at(range.end, suffix)
 6014                    {
 6015                        range.end += lookahead;
 6016                    }
 6017                }
 6018                range
 6019            };
 6020
 6021            ranges.push(range.clone());
 6022
 6023            if !self.linked_edit_ranges.is_empty() {
 6024                let start_anchor = snapshot.anchor_before(range.start);
 6025                let end_anchor = snapshot.anchor_after(range.end);
 6026                if let Some(ranges) = self
 6027                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 6028                {
 6029                    for (buffer, edits) in ranges {
 6030                        linked_edits
 6031                            .entry(buffer.clone())
 6032                            .or_default()
 6033                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 6034                    }
 6035                }
 6036            }
 6037        }
 6038
 6039        let common_prefix_len = old_text
 6040            .chars()
 6041            .zip(new_text.chars())
 6042            .take_while(|(a, b)| a == b)
 6043            .map(|(a, _)| a.len_utf8())
 6044            .sum::<usize>();
 6045
 6046        cx.emit(EditorEvent::InputHandled {
 6047            utf16_range_to_replace: None,
 6048            text: new_text[common_prefix_len..].into(),
 6049        });
 6050
 6051        self.transact(window, cx, |editor, window, cx| {
 6052            if let Some(mut snippet) = snippet {
 6053                snippet.text = new_text.to_string();
 6054                editor
 6055                    .insert_snippet(&ranges, snippet, window, cx)
 6056                    .log_err();
 6057            } else {
 6058                editor.buffer.update(cx, |multi_buffer, cx| {
 6059                    let auto_indent = match completion.insert_text_mode {
 6060                        Some(InsertTextMode::AS_IS) => None,
 6061                        _ => editor.autoindent_mode.clone(),
 6062                    };
 6063                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 6064                    multi_buffer.edit(edits, auto_indent, cx);
 6065                });
 6066            }
 6067            for (buffer, edits) in linked_edits {
 6068                buffer.update(cx, |buffer, cx| {
 6069                    let snapshot = buffer.snapshot();
 6070                    let edits = edits
 6071                        .into_iter()
 6072                        .map(|(range, text)| {
 6073                            use text::ToPoint as TP;
 6074                            let end_point = TP::to_point(&range.end, &snapshot);
 6075                            let start_point = TP::to_point(&range.start, &snapshot);
 6076                            (start_point..end_point, text)
 6077                        })
 6078                        .sorted_by_key(|(range, _)| range.start);
 6079                    buffer.edit(edits, None, cx);
 6080                })
 6081            }
 6082
 6083            editor.refresh_edit_prediction(true, false, window, cx);
 6084        });
 6085        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors_arc(), &snapshot);
 6086
 6087        let show_new_completions_on_confirm = completion
 6088            .confirm
 6089            .as_ref()
 6090            .is_some_and(|confirm| confirm(intent, window, cx));
 6091        if show_new_completions_on_confirm {
 6092            self.open_or_update_completions_menu(None, None, false, window, cx);
 6093        }
 6094
 6095        let provider = self.completion_provider.as_ref()?;
 6096        drop(completion);
 6097        let apply_edits = provider.apply_additional_edits_for_completion(
 6098            buffer_handle,
 6099            completions_menu.completions.clone(),
 6100            candidate_id,
 6101            true,
 6102            cx,
 6103        );
 6104
 6105        let editor_settings = EditorSettings::get_global(cx);
 6106        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 6107            // After the code completion is finished, users often want to know what signatures are needed.
 6108            // so we should automatically call signature_help
 6109            self.show_signature_help(&ShowSignatureHelp, window, cx);
 6110        }
 6111
 6112        Some(cx.foreground_executor().spawn(async move {
 6113            apply_edits.await?;
 6114            Ok(())
 6115        }))
 6116    }
 6117
 6118    pub fn toggle_code_actions(
 6119        &mut self,
 6120        action: &ToggleCodeActions,
 6121        window: &mut Window,
 6122        cx: &mut Context<Self>,
 6123    ) {
 6124        let quick_launch = action.quick_launch;
 6125        let mut context_menu = self.context_menu.borrow_mut();
 6126        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 6127            if code_actions.deployed_from == action.deployed_from {
 6128                // Toggle if we're selecting the same one
 6129                *context_menu = None;
 6130                cx.notify();
 6131                return;
 6132            } else {
 6133                // Otherwise, clear it and start a new one
 6134                *context_menu = None;
 6135                cx.notify();
 6136            }
 6137        }
 6138        drop(context_menu);
 6139        let snapshot = self.snapshot(window, cx);
 6140        let deployed_from = action.deployed_from.clone();
 6141        let action = action.clone();
 6142        self.completion_tasks.clear();
 6143        self.discard_edit_prediction(false, cx);
 6144
 6145        let multibuffer_point = match &action.deployed_from {
 6146            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 6147                DisplayPoint::new(*row, 0).to_point(&snapshot)
 6148            }
 6149            _ => self
 6150                .selections
 6151                .newest::<Point>(&snapshot.display_snapshot)
 6152                .head(),
 6153        };
 6154        let Some((buffer, buffer_row)) = snapshot
 6155            .buffer_snapshot()
 6156            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 6157            .and_then(|(buffer_snapshot, range)| {
 6158                self.buffer()
 6159                    .read(cx)
 6160                    .buffer(buffer_snapshot.remote_id())
 6161                    .map(|buffer| (buffer, range.start.row))
 6162            })
 6163        else {
 6164            return;
 6165        };
 6166        let buffer_id = buffer.read(cx).remote_id();
 6167        let tasks = self
 6168            .tasks
 6169            .get(&(buffer_id, buffer_row))
 6170            .map(|t| Arc::new(t.to_owned()));
 6171
 6172        if !self.focus_handle.is_focused(window) {
 6173            return;
 6174        }
 6175        let project = self.project.clone();
 6176
 6177        let code_actions_task = match deployed_from {
 6178            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 6179            _ => self.code_actions(buffer_row, window, cx),
 6180        };
 6181
 6182        let runnable_task = match deployed_from {
 6183            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 6184            _ => {
 6185                let mut task_context_task = Task::ready(None);
 6186                if let Some(tasks) = &tasks
 6187                    && let Some(project) = project
 6188                {
 6189                    task_context_task =
 6190                        Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx);
 6191                }
 6192
 6193                cx.spawn_in(window, {
 6194                    let buffer = buffer.clone();
 6195                    async move |editor, cx| {
 6196                        let task_context = task_context_task.await;
 6197
 6198                        let resolved_tasks =
 6199                            tasks
 6200                                .zip(task_context.clone())
 6201                                .map(|(tasks, task_context)| ResolvedTasks {
 6202                                    templates: tasks.resolve(&task_context).collect(),
 6203                                    position: snapshot.buffer_snapshot().anchor_before(Point::new(
 6204                                        multibuffer_point.row,
 6205                                        tasks.column,
 6206                                    )),
 6207                                });
 6208                        let debug_scenarios = editor
 6209                            .update(cx, |editor, cx| {
 6210                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 6211                            })?
 6212                            .await;
 6213                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 6214                    }
 6215                })
 6216            }
 6217        };
 6218
 6219        cx.spawn_in(window, async move |editor, cx| {
 6220            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 6221            let code_actions = code_actions_task.await;
 6222            let spawn_straight_away = quick_launch
 6223                && resolved_tasks
 6224                    .as_ref()
 6225                    .is_some_and(|tasks| tasks.templates.len() == 1)
 6226                && code_actions
 6227                    .as_ref()
 6228                    .is_none_or(|actions| actions.is_empty())
 6229                && debug_scenarios.is_empty();
 6230
 6231            editor.update_in(cx, |editor, window, cx| {
 6232                crate::hover_popover::hide_hover(editor, cx);
 6233                let actions = CodeActionContents::new(
 6234                    resolved_tasks,
 6235                    code_actions,
 6236                    debug_scenarios,
 6237                    task_context.unwrap_or_default(),
 6238                );
 6239
 6240                // Don't show the menu if there are no actions available
 6241                if actions.is_empty() {
 6242                    cx.notify();
 6243                    return Task::ready(Ok(()));
 6244                }
 6245
 6246                *editor.context_menu.borrow_mut() =
 6247                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 6248                        buffer,
 6249                        actions,
 6250                        selected_item: Default::default(),
 6251                        scroll_handle: UniformListScrollHandle::default(),
 6252                        deployed_from,
 6253                    }));
 6254                cx.notify();
 6255                if spawn_straight_away
 6256                    && let Some(task) = editor.confirm_code_action(
 6257                        &ConfirmCodeAction { item_ix: Some(0) },
 6258                        window,
 6259                        cx,
 6260                    )
 6261                {
 6262                    return task;
 6263                }
 6264
 6265                Task::ready(Ok(()))
 6266            })
 6267        })
 6268        .detach_and_log_err(cx);
 6269    }
 6270
 6271    fn debug_scenarios(
 6272        &mut self,
 6273        resolved_tasks: &Option<ResolvedTasks>,
 6274        buffer: &Entity<Buffer>,
 6275        cx: &mut App,
 6276    ) -> Task<Vec<task::DebugScenario>> {
 6277        maybe!({
 6278            let project = self.project()?;
 6279            let dap_store = project.read(cx).dap_store();
 6280            let mut scenarios = vec![];
 6281            let resolved_tasks = resolved_tasks.as_ref()?;
 6282            let buffer = buffer.read(cx);
 6283            let language = buffer.language()?;
 6284            let file = buffer.file();
 6285            let debug_adapter = language_settings(language.name().into(), file, cx)
 6286                .debuggers
 6287                .first()
 6288                .map(SharedString::from)
 6289                .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 6290
 6291            dap_store.update(cx, |dap_store, cx| {
 6292                for (_, task) in &resolved_tasks.templates {
 6293                    let maybe_scenario = dap_store.debug_scenario_for_build_task(
 6294                        task.original_task().clone(),
 6295                        debug_adapter.clone().into(),
 6296                        task.display_label().to_owned().into(),
 6297                        cx,
 6298                    );
 6299                    scenarios.push(maybe_scenario);
 6300                }
 6301            });
 6302            Some(cx.background_spawn(async move {
 6303                futures::future::join_all(scenarios)
 6304                    .await
 6305                    .into_iter()
 6306                    .flatten()
 6307                    .collect::<Vec<_>>()
 6308            }))
 6309        })
 6310        .unwrap_or_else(|| Task::ready(vec![]))
 6311    }
 6312
 6313    fn code_actions(
 6314        &mut self,
 6315        buffer_row: u32,
 6316        window: &mut Window,
 6317        cx: &mut Context<Self>,
 6318    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 6319        let mut task = self.code_actions_task.take();
 6320        cx.spawn_in(window, async move |editor, cx| {
 6321            while let Some(prev_task) = task {
 6322                prev_task.await.log_err();
 6323                task = editor
 6324                    .update(cx, |this, _| this.code_actions_task.take())
 6325                    .ok()?;
 6326            }
 6327
 6328            editor
 6329                .update(cx, |editor, cx| {
 6330                    editor
 6331                        .available_code_actions
 6332                        .clone()
 6333                        .and_then(|(location, code_actions)| {
 6334                            let snapshot = location.buffer.read(cx).snapshot();
 6335                            let point_range = location.range.to_point(&snapshot);
 6336                            let point_range = point_range.start.row..=point_range.end.row;
 6337                            if point_range.contains(&buffer_row) {
 6338                                Some(code_actions)
 6339                            } else {
 6340                                None
 6341                            }
 6342                        })
 6343                })
 6344                .ok()
 6345                .flatten()
 6346        })
 6347    }
 6348
 6349    pub fn confirm_code_action(
 6350        &mut self,
 6351        action: &ConfirmCodeAction,
 6352        window: &mut Window,
 6353        cx: &mut Context<Self>,
 6354    ) -> Option<Task<Result<()>>> {
 6355        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6356
 6357        let actions_menu =
 6358            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 6359                menu
 6360            } else {
 6361                return None;
 6362            };
 6363
 6364        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 6365        let action = actions_menu.actions.get(action_ix)?;
 6366        let title = action.label();
 6367        let buffer = actions_menu.buffer;
 6368        let workspace = self.workspace()?;
 6369
 6370        match action {
 6371            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 6372                workspace.update(cx, |workspace, cx| {
 6373                    workspace.schedule_resolved_task(
 6374                        task_source_kind,
 6375                        resolved_task,
 6376                        false,
 6377                        window,
 6378                        cx,
 6379                    );
 6380
 6381                    Some(Task::ready(Ok(())))
 6382                })
 6383            }
 6384            CodeActionsItem::CodeAction {
 6385                excerpt_id,
 6386                action,
 6387                provider,
 6388            } => {
 6389                let apply_code_action =
 6390                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 6391                let workspace = workspace.downgrade();
 6392                Some(cx.spawn_in(window, async move |editor, cx| {
 6393                    let project_transaction = apply_code_action.await?;
 6394                    Self::open_project_transaction(
 6395                        &editor,
 6396                        workspace,
 6397                        project_transaction,
 6398                        title,
 6399                        cx,
 6400                    )
 6401                    .await
 6402                }))
 6403            }
 6404            CodeActionsItem::DebugScenario(scenario) => {
 6405                let context = actions_menu.actions.context;
 6406
 6407                workspace.update(cx, |workspace, cx| {
 6408                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 6409                    workspace.start_debug_session(
 6410                        scenario,
 6411                        context,
 6412                        Some(buffer),
 6413                        None,
 6414                        window,
 6415                        cx,
 6416                    );
 6417                });
 6418                Some(Task::ready(Ok(())))
 6419            }
 6420        }
 6421    }
 6422
 6423    pub async fn open_project_transaction(
 6424        editor: &WeakEntity<Editor>,
 6425        workspace: WeakEntity<Workspace>,
 6426        transaction: ProjectTransaction,
 6427        title: String,
 6428        cx: &mut AsyncWindowContext,
 6429    ) -> Result<()> {
 6430        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 6431        cx.update(|_, cx| {
 6432            entries.sort_unstable_by_key(|(buffer, _)| {
 6433                buffer.read(cx).file().map(|f| f.path().clone())
 6434            });
 6435        })?;
 6436        if entries.is_empty() {
 6437            return Ok(());
 6438        }
 6439
 6440        // If the project transaction's edits are all contained within this editor, then
 6441        // avoid opening a new editor to display them.
 6442
 6443        if let [(buffer, transaction)] = &*entries {
 6444            let excerpt = editor.update(cx, |editor, cx| {
 6445                editor
 6446                    .buffer()
 6447                    .read(cx)
 6448                    .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6449            })?;
 6450            if let Some((_, excerpted_buffer, excerpt_range)) = excerpt
 6451                && excerpted_buffer == *buffer
 6452            {
 6453                let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6454                    let excerpt_range = excerpt_range.to_offset(buffer);
 6455                    buffer
 6456                        .edited_ranges_for_transaction::<usize>(transaction)
 6457                        .all(|range| {
 6458                            excerpt_range.start <= range.start && excerpt_range.end >= range.end
 6459                        })
 6460                })?;
 6461
 6462                if all_edits_within_excerpt {
 6463                    return Ok(());
 6464                }
 6465            }
 6466        }
 6467
 6468        let mut ranges_to_highlight = Vec::new();
 6469        let excerpt_buffer = cx.new(|cx| {
 6470            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6471            for (buffer_handle, transaction) in &entries {
 6472                let edited_ranges = buffer_handle
 6473                    .read(cx)
 6474                    .edited_ranges_for_transaction::<Point>(transaction)
 6475                    .collect::<Vec<_>>();
 6476                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6477                    PathKey::for_buffer(buffer_handle, cx),
 6478                    buffer_handle.clone(),
 6479                    edited_ranges,
 6480                    multibuffer_context_lines(cx),
 6481                    cx,
 6482                );
 6483
 6484                ranges_to_highlight.extend(ranges);
 6485            }
 6486            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6487            multibuffer
 6488        })?;
 6489
 6490        workspace.update_in(cx, |workspace, window, cx| {
 6491            let project = workspace.project().clone();
 6492            let editor =
 6493                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6494            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6495            editor.update(cx, |editor, cx| {
 6496                editor.highlight_background::<Self>(
 6497                    &ranges_to_highlight,
 6498                    |theme| theme.colors().editor_highlighted_line_background,
 6499                    cx,
 6500                );
 6501            });
 6502        })?;
 6503
 6504        Ok(())
 6505    }
 6506
 6507    pub fn clear_code_action_providers(&mut self) {
 6508        self.code_action_providers.clear();
 6509        self.available_code_actions.take();
 6510    }
 6511
 6512    pub fn add_code_action_provider(
 6513        &mut self,
 6514        provider: Rc<dyn CodeActionProvider>,
 6515        window: &mut Window,
 6516        cx: &mut Context<Self>,
 6517    ) {
 6518        if self
 6519            .code_action_providers
 6520            .iter()
 6521            .any(|existing_provider| existing_provider.id() == provider.id())
 6522        {
 6523            return;
 6524        }
 6525
 6526        self.code_action_providers.push(provider);
 6527        self.refresh_code_actions(window, cx);
 6528    }
 6529
 6530    pub fn remove_code_action_provider(
 6531        &mut self,
 6532        id: Arc<str>,
 6533        window: &mut Window,
 6534        cx: &mut Context<Self>,
 6535    ) {
 6536        self.code_action_providers
 6537            .retain(|provider| provider.id() != id);
 6538        self.refresh_code_actions(window, cx);
 6539    }
 6540
 6541    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6542        !self.code_action_providers.is_empty()
 6543            && EditorSettings::get_global(cx).toolbar.code_actions
 6544    }
 6545
 6546    pub fn has_available_code_actions(&self) -> bool {
 6547        self.available_code_actions
 6548            .as_ref()
 6549            .is_some_and(|(_, actions)| !actions.is_empty())
 6550    }
 6551
 6552    fn render_inline_code_actions(
 6553        &self,
 6554        icon_size: ui::IconSize,
 6555        display_row: DisplayRow,
 6556        is_active: bool,
 6557        cx: &mut Context<Self>,
 6558    ) -> AnyElement {
 6559        let show_tooltip = !self.context_menu_visible();
 6560        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6561            .icon_size(icon_size)
 6562            .shape(ui::IconButtonShape::Square)
 6563            .icon_color(ui::Color::Hidden)
 6564            .toggle_state(is_active)
 6565            .when(show_tooltip, |this| {
 6566                this.tooltip({
 6567                    let focus_handle = self.focus_handle.clone();
 6568                    move |_window, cx| {
 6569                        Tooltip::for_action_in(
 6570                            "Toggle Code Actions",
 6571                            &ToggleCodeActions {
 6572                                deployed_from: None,
 6573                                quick_launch: false,
 6574                            },
 6575                            &focus_handle,
 6576                            cx,
 6577                        )
 6578                    }
 6579                })
 6580            })
 6581            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6582                window.focus(&editor.focus_handle(cx));
 6583                editor.toggle_code_actions(
 6584                    &crate::actions::ToggleCodeActions {
 6585                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6586                            display_row,
 6587                        )),
 6588                        quick_launch: false,
 6589                    },
 6590                    window,
 6591                    cx,
 6592                );
 6593            }))
 6594            .into_any_element()
 6595    }
 6596
 6597    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6598        &self.context_menu
 6599    }
 6600
 6601    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6602        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6603            cx.background_executor()
 6604                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6605                .await;
 6606
 6607            let (start_buffer, start, _, end, newest_selection) = this
 6608                .update(cx, |this, cx| {
 6609                    let newest_selection = this.selections.newest_anchor().clone();
 6610                    if newest_selection.head().diff_base_anchor.is_some() {
 6611                        return None;
 6612                    }
 6613                    let display_snapshot = this.display_snapshot(cx);
 6614                    let newest_selection_adjusted =
 6615                        this.selections.newest_adjusted(&display_snapshot);
 6616                    let buffer = this.buffer.read(cx);
 6617
 6618                    let (start_buffer, start) =
 6619                        buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6620                    let (end_buffer, end) =
 6621                        buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6622
 6623                    Some((start_buffer, start, end_buffer, end, newest_selection))
 6624                })?
 6625                .filter(|(start_buffer, _, end_buffer, _, _)| start_buffer == end_buffer)
 6626                .context(
 6627                    "Expected selection to lie in a single buffer when refreshing code actions",
 6628                )?;
 6629            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6630                let providers = this.code_action_providers.clone();
 6631                let tasks = this
 6632                    .code_action_providers
 6633                    .iter()
 6634                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6635                    .collect::<Vec<_>>();
 6636                (providers, tasks)
 6637            })?;
 6638
 6639            let mut actions = Vec::new();
 6640            for (provider, provider_actions) in
 6641                providers.into_iter().zip(future::join_all(tasks).await)
 6642            {
 6643                if let Some(provider_actions) = provider_actions.log_err() {
 6644                    actions.extend(provider_actions.into_iter().map(|action| {
 6645                        AvailableCodeAction {
 6646                            excerpt_id: newest_selection.start.excerpt_id,
 6647                            action,
 6648                            provider: provider.clone(),
 6649                        }
 6650                    }));
 6651                }
 6652            }
 6653
 6654            this.update(cx, |this, cx| {
 6655                this.available_code_actions = if actions.is_empty() {
 6656                    None
 6657                } else {
 6658                    Some((
 6659                        Location {
 6660                            buffer: start_buffer,
 6661                            range: start..end,
 6662                        },
 6663                        actions.into(),
 6664                    ))
 6665                };
 6666                cx.notify();
 6667            })
 6668        }));
 6669    }
 6670
 6671    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6672        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6673            self.show_git_blame_inline = false;
 6674
 6675            self.show_git_blame_inline_delay_task =
 6676                Some(cx.spawn_in(window, async move |this, cx| {
 6677                    cx.background_executor().timer(delay).await;
 6678
 6679                    this.update(cx, |this, cx| {
 6680                        this.show_git_blame_inline = true;
 6681                        cx.notify();
 6682                    })
 6683                    .log_err();
 6684                }));
 6685        }
 6686    }
 6687
 6688    pub fn blame_hover(&mut self, _: &BlameHover, window: &mut Window, cx: &mut Context<Self>) {
 6689        let snapshot = self.snapshot(window, cx);
 6690        let cursor = self
 6691            .selections
 6692            .newest::<Point>(&snapshot.display_snapshot)
 6693            .head();
 6694        let Some((buffer, point, _)) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)
 6695        else {
 6696            return;
 6697        };
 6698
 6699        let Some(blame) = self.blame.as_ref() else {
 6700            return;
 6701        };
 6702
 6703        let row_info = RowInfo {
 6704            buffer_id: Some(buffer.remote_id()),
 6705            buffer_row: Some(point.row),
 6706            ..Default::default()
 6707        };
 6708        let Some((buffer, blame_entry)) = blame
 6709            .update(cx, |blame, cx| blame.blame_for_rows(&[row_info], cx).next())
 6710            .flatten()
 6711        else {
 6712            return;
 6713        };
 6714
 6715        let anchor = self.selections.newest_anchor().head();
 6716        let position = self.to_pixel_point(anchor, &snapshot, window);
 6717        if let (Some(position), Some(last_bounds)) = (position, self.last_bounds) {
 6718            self.show_blame_popover(
 6719                buffer,
 6720                &blame_entry,
 6721                position + last_bounds.origin,
 6722                true,
 6723                cx,
 6724            );
 6725        };
 6726    }
 6727
 6728    fn show_blame_popover(
 6729        &mut self,
 6730        buffer: BufferId,
 6731        blame_entry: &BlameEntry,
 6732        position: gpui::Point<Pixels>,
 6733        ignore_timeout: bool,
 6734        cx: &mut Context<Self>,
 6735    ) {
 6736        if let Some(state) = &mut self.inline_blame_popover {
 6737            state.hide_task.take();
 6738        } else {
 6739            let blame_popover_delay = EditorSettings::get_global(cx).hover_popover_delay.0;
 6740            let blame_entry = blame_entry.clone();
 6741            let show_task = cx.spawn(async move |editor, cx| {
 6742                if !ignore_timeout {
 6743                    cx.background_executor()
 6744                        .timer(std::time::Duration::from_millis(blame_popover_delay))
 6745                        .await;
 6746                }
 6747                editor
 6748                    .update(cx, |editor, cx| {
 6749                        editor.inline_blame_popover_show_task.take();
 6750                        let Some(blame) = editor.blame.as_ref() else {
 6751                            return;
 6752                        };
 6753                        let blame = blame.read(cx);
 6754                        let details = blame.details_for_entry(buffer, &blame_entry);
 6755                        let markdown = cx.new(|cx| {
 6756                            Markdown::new(
 6757                                details
 6758                                    .as_ref()
 6759                                    .map(|message| message.message.clone())
 6760                                    .unwrap_or_default(),
 6761                                None,
 6762                                None,
 6763                                cx,
 6764                            )
 6765                        });
 6766                        editor.inline_blame_popover = Some(InlineBlamePopover {
 6767                            position,
 6768                            hide_task: None,
 6769                            popover_bounds: None,
 6770                            popover_state: InlineBlamePopoverState {
 6771                                scroll_handle: ScrollHandle::new(),
 6772                                commit_message: details,
 6773                                markdown,
 6774                            },
 6775                            keyboard_grace: ignore_timeout,
 6776                        });
 6777                        cx.notify();
 6778                    })
 6779                    .ok();
 6780            });
 6781            self.inline_blame_popover_show_task = Some(show_task);
 6782        }
 6783    }
 6784
 6785    fn hide_blame_popover(&mut self, ignore_timeout: bool, cx: &mut Context<Self>) -> bool {
 6786        self.inline_blame_popover_show_task.take();
 6787        if let Some(state) = &mut self.inline_blame_popover {
 6788            let hide_task = cx.spawn(async move |editor, cx| {
 6789                if !ignore_timeout {
 6790                    cx.background_executor()
 6791                        .timer(std::time::Duration::from_millis(100))
 6792                        .await;
 6793                }
 6794                editor
 6795                    .update(cx, |editor, cx| {
 6796                        editor.inline_blame_popover.take();
 6797                        cx.notify();
 6798                    })
 6799                    .ok();
 6800            });
 6801            state.hide_task = Some(hide_task);
 6802            true
 6803        } else {
 6804            false
 6805        }
 6806    }
 6807
 6808    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 6809        if self.pending_rename.is_some() {
 6810            return None;
 6811        }
 6812
 6813        let provider = self.semantics_provider.clone()?;
 6814        let buffer = self.buffer.read(cx);
 6815        let newest_selection = self.selections.newest_anchor().clone();
 6816        let cursor_position = newest_selection.head();
 6817        let (cursor_buffer, cursor_buffer_position) =
 6818            buffer.text_anchor_for_position(cursor_position, cx)?;
 6819        let (tail_buffer, tail_buffer_position) =
 6820            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 6821        if cursor_buffer != tail_buffer {
 6822            return None;
 6823        }
 6824
 6825        let snapshot = cursor_buffer.read(cx).snapshot();
 6826        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position, None);
 6827        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position, None);
 6828        if start_word_range != end_word_range {
 6829            self.document_highlights_task.take();
 6830            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6831            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6832            return None;
 6833        }
 6834
 6835        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce.0;
 6836        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6837            cx.background_executor()
 6838                .timer(Duration::from_millis(debounce))
 6839                .await;
 6840
 6841            let highlights = if let Some(highlights) = cx
 6842                .update(|cx| {
 6843                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 6844                })
 6845                .ok()
 6846                .flatten()
 6847            {
 6848                highlights.await.log_err()
 6849            } else {
 6850                None
 6851            };
 6852
 6853            if let Some(highlights) = highlights {
 6854                this.update(cx, |this, cx| {
 6855                    if this.pending_rename.is_some() {
 6856                        return;
 6857                    }
 6858
 6859                    let buffer = this.buffer.read(cx);
 6860                    if buffer
 6861                        .text_anchor_for_position(cursor_position, cx)
 6862                        .is_none_or(|(buffer, _)| buffer != cursor_buffer)
 6863                    {
 6864                        return;
 6865                    }
 6866
 6867                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 6868                    let mut write_ranges = Vec::new();
 6869                    let mut read_ranges = Vec::new();
 6870                    for highlight in highlights {
 6871                        let buffer_id = cursor_buffer.read(cx).remote_id();
 6872                        for (excerpt_id, excerpt_range) in buffer.excerpts_for_buffer(buffer_id, cx)
 6873                        {
 6874                            let start = highlight
 6875                                .range
 6876                                .start
 6877                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 6878                            let end = highlight
 6879                                .range
 6880                                .end
 6881                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6882                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6883                                continue;
 6884                            }
 6885
 6886                            let range =
 6887                                Anchor::range_in_buffer(excerpt_id, buffer_id, *start..*end);
 6888                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 6889                                write_ranges.push(range);
 6890                            } else {
 6891                                read_ranges.push(range);
 6892                            }
 6893                        }
 6894                    }
 6895
 6896                    this.highlight_background::<DocumentHighlightRead>(
 6897                        &read_ranges,
 6898                        |theme| theme.colors().editor_document_highlight_read_background,
 6899                        cx,
 6900                    );
 6901                    this.highlight_background::<DocumentHighlightWrite>(
 6902                        &write_ranges,
 6903                        |theme| theme.colors().editor_document_highlight_write_background,
 6904                        cx,
 6905                    );
 6906                    cx.notify();
 6907                })
 6908                .log_err();
 6909            }
 6910        }));
 6911        None
 6912    }
 6913
 6914    fn prepare_highlight_query_from_selection(
 6915        &mut self,
 6916        window: &Window,
 6917        cx: &mut Context<Editor>,
 6918    ) -> Option<(String, Range<Anchor>)> {
 6919        if matches!(self.mode, EditorMode::SingleLine) {
 6920            return None;
 6921        }
 6922        if !EditorSettings::get_global(cx).selection_highlight {
 6923            return None;
 6924        }
 6925        if self.selections.count() != 1 || self.selections.line_mode() {
 6926            return None;
 6927        }
 6928        let snapshot = self.snapshot(window, cx);
 6929        let selection = self.selections.newest::<Point>(&snapshot);
 6930        // If the selection spans multiple rows OR it is empty
 6931        if selection.start.row != selection.end.row
 6932            || selection.start.column == selection.end.column
 6933        {
 6934            return None;
 6935        }
 6936        let selection_anchor_range = selection.range().to_anchors(snapshot.buffer_snapshot());
 6937        let query = snapshot
 6938            .buffer_snapshot()
 6939            .text_for_range(selection_anchor_range.clone())
 6940            .collect::<String>();
 6941        if query.trim().is_empty() {
 6942            return None;
 6943        }
 6944        Some((query, selection_anchor_range))
 6945    }
 6946
 6947    fn update_selection_occurrence_highlights(
 6948        &mut self,
 6949        query_text: String,
 6950        query_range: Range<Anchor>,
 6951        multi_buffer_range_to_query: Range<Point>,
 6952        use_debounce: bool,
 6953        window: &mut Window,
 6954        cx: &mut Context<Editor>,
 6955    ) -> Task<()> {
 6956        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6957        cx.spawn_in(window, async move |editor, cx| {
 6958            if use_debounce {
 6959                cx.background_executor()
 6960                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 6961                    .await;
 6962            }
 6963            let match_task = cx.background_spawn(async move {
 6964                let buffer_ranges = multi_buffer_snapshot
 6965                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 6966                    .into_iter()
 6967                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 6968                let mut match_ranges = Vec::new();
 6969                let Ok(regex) = project::search::SearchQuery::text(
 6970                    query_text.clone(),
 6971                    false,
 6972                    false,
 6973                    false,
 6974                    Default::default(),
 6975                    Default::default(),
 6976                    false,
 6977                    None,
 6978                ) else {
 6979                    return Vec::default();
 6980                };
 6981                let query_range = query_range.to_anchors(&multi_buffer_snapshot);
 6982                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 6983                    match_ranges.extend(
 6984                        regex
 6985                            .search(buffer_snapshot, Some(search_range.clone()))
 6986                            .await
 6987                            .into_iter()
 6988                            .filter_map(|match_range| {
 6989                                let match_start = buffer_snapshot
 6990                                    .anchor_after(search_range.start + match_range.start);
 6991                                let match_end = buffer_snapshot
 6992                                    .anchor_before(search_range.start + match_range.end);
 6993                                let match_anchor_range = Anchor::range_in_buffer(
 6994                                    excerpt_id,
 6995                                    buffer_snapshot.remote_id(),
 6996                                    match_start..match_end,
 6997                                );
 6998                                (match_anchor_range != query_range).then_some(match_anchor_range)
 6999                            }),
 7000                    );
 7001                }
 7002                match_ranges
 7003            });
 7004            let match_ranges = match_task.await;
 7005            editor
 7006                .update_in(cx, |editor, _, cx| {
 7007                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 7008                    if !match_ranges.is_empty() {
 7009                        editor.highlight_background::<SelectedTextHighlight>(
 7010                            &match_ranges,
 7011                            |theme| theme.colors().editor_document_highlight_bracket_background,
 7012                            cx,
 7013                        )
 7014                    }
 7015                })
 7016                .log_err();
 7017        })
 7018    }
 7019
 7020    fn refresh_single_line_folds(&mut self, window: &mut Window, cx: &mut Context<Editor>) {
 7021        struct NewlineFold;
 7022        let type_id = std::any::TypeId::of::<NewlineFold>();
 7023        if !self.mode.is_single_line() {
 7024            return;
 7025        }
 7026        let snapshot = self.snapshot(window, cx);
 7027        if snapshot.buffer_snapshot().max_point().row == 0 {
 7028            return;
 7029        }
 7030        let task = cx.background_spawn(async move {
 7031            let new_newlines = snapshot
 7032                .buffer_chars_at(0)
 7033                .filter_map(|(c, i)| {
 7034                    if c == '\n' {
 7035                        Some(
 7036                            snapshot.buffer_snapshot().anchor_after(i)
 7037                                ..snapshot.buffer_snapshot().anchor_before(i + 1),
 7038                        )
 7039                    } else {
 7040                        None
 7041                    }
 7042                })
 7043                .collect::<Vec<_>>();
 7044            let existing_newlines = snapshot
 7045                .folds_in_range(0..snapshot.buffer_snapshot().len())
 7046                .filter_map(|fold| {
 7047                    if fold.placeholder.type_tag == Some(type_id) {
 7048                        Some(fold.range.start..fold.range.end)
 7049                    } else {
 7050                        None
 7051                    }
 7052                })
 7053                .collect::<Vec<_>>();
 7054
 7055            (new_newlines, existing_newlines)
 7056        });
 7057        self.folding_newlines = cx.spawn(async move |this, cx| {
 7058            let (new_newlines, existing_newlines) = task.await;
 7059            if new_newlines == existing_newlines {
 7060                return;
 7061            }
 7062            let placeholder = FoldPlaceholder {
 7063                render: Arc::new(move |_, _, cx| {
 7064                    div()
 7065                        .bg(cx.theme().status().hint_background)
 7066                        .border_b_1()
 7067                        .size_full()
 7068                        .font(ThemeSettings::get_global(cx).buffer_font.clone())
 7069                        .border_color(cx.theme().status().hint)
 7070                        .child("\\n")
 7071                        .into_any()
 7072                }),
 7073                constrain_width: false,
 7074                merge_adjacent: false,
 7075                type_tag: Some(type_id),
 7076            };
 7077            let creases = new_newlines
 7078                .into_iter()
 7079                .map(|range| Crease::simple(range, placeholder.clone()))
 7080                .collect();
 7081            this.update(cx, |this, cx| {
 7082                this.display_map.update(cx, |display_map, cx| {
 7083                    display_map.remove_folds_with_type(existing_newlines, type_id, cx);
 7084                    display_map.fold(creases, cx);
 7085                });
 7086            })
 7087            .ok();
 7088        });
 7089    }
 7090
 7091    fn refresh_selected_text_highlights(
 7092        &mut self,
 7093        on_buffer_edit: bool,
 7094        window: &mut Window,
 7095        cx: &mut Context<Editor>,
 7096    ) {
 7097        let Some((query_text, query_range)) =
 7098            self.prepare_highlight_query_from_selection(window, cx)
 7099        else {
 7100            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 7101            self.quick_selection_highlight_task.take();
 7102            self.debounced_selection_highlight_task.take();
 7103            return;
 7104        };
 7105        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 7106        if on_buffer_edit
 7107            || self
 7108                .quick_selection_highlight_task
 7109                .as_ref()
 7110                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7111        {
 7112            let multi_buffer_visible_start = self
 7113                .scroll_manager
 7114                .anchor()
 7115                .anchor
 7116                .to_point(&multi_buffer_snapshot);
 7117            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 7118                multi_buffer_visible_start
 7119                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 7120                Bias::Left,
 7121            );
 7122            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 7123            self.quick_selection_highlight_task = Some((
 7124                query_range.clone(),
 7125                self.update_selection_occurrence_highlights(
 7126                    query_text.clone(),
 7127                    query_range.clone(),
 7128                    multi_buffer_visible_range,
 7129                    false,
 7130                    window,
 7131                    cx,
 7132                ),
 7133            ));
 7134        }
 7135        if on_buffer_edit
 7136            || self
 7137                .debounced_selection_highlight_task
 7138                .as_ref()
 7139                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7140        {
 7141            let multi_buffer_start = multi_buffer_snapshot
 7142                .anchor_before(0)
 7143                .to_point(&multi_buffer_snapshot);
 7144            let multi_buffer_end = multi_buffer_snapshot
 7145                .anchor_after(multi_buffer_snapshot.len())
 7146                .to_point(&multi_buffer_snapshot);
 7147            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 7148            self.debounced_selection_highlight_task = Some((
 7149                query_range.clone(),
 7150                self.update_selection_occurrence_highlights(
 7151                    query_text,
 7152                    query_range,
 7153                    multi_buffer_full_range,
 7154                    true,
 7155                    window,
 7156                    cx,
 7157                ),
 7158            ));
 7159        }
 7160    }
 7161
 7162    pub fn refresh_edit_prediction(
 7163        &mut self,
 7164        debounce: bool,
 7165        user_requested: bool,
 7166        window: &mut Window,
 7167        cx: &mut Context<Self>,
 7168    ) -> Option<()> {
 7169        if DisableAiSettings::get_global(cx).disable_ai {
 7170            return None;
 7171        }
 7172
 7173        let provider = self.edit_prediction_provider()?;
 7174        let cursor = self.selections.newest_anchor().head();
 7175        let (buffer, cursor_buffer_position) =
 7176            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7177
 7178        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 7179            self.discard_edit_prediction(false, cx);
 7180            return None;
 7181        }
 7182
 7183        self.update_visible_edit_prediction(window, cx);
 7184
 7185        if !user_requested
 7186            && (!self.should_show_edit_predictions()
 7187                || !self.is_focused(window)
 7188                || buffer.read(cx).is_empty())
 7189        {
 7190            self.discard_edit_prediction(false, cx);
 7191            return None;
 7192        }
 7193
 7194        provider.refresh(buffer, cursor_buffer_position, debounce, cx);
 7195        Some(())
 7196    }
 7197
 7198    fn show_edit_predictions_in_menu(&self) -> bool {
 7199        match self.edit_prediction_settings {
 7200            EditPredictionSettings::Disabled => false,
 7201            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 7202        }
 7203    }
 7204
 7205    pub fn edit_predictions_enabled(&self) -> bool {
 7206        match self.edit_prediction_settings {
 7207            EditPredictionSettings::Disabled => false,
 7208            EditPredictionSettings::Enabled { .. } => true,
 7209        }
 7210    }
 7211
 7212    fn edit_prediction_requires_modifier(&self) -> bool {
 7213        match self.edit_prediction_settings {
 7214            EditPredictionSettings::Disabled => false,
 7215            EditPredictionSettings::Enabled {
 7216                preview_requires_modifier,
 7217                ..
 7218            } => preview_requires_modifier,
 7219        }
 7220    }
 7221
 7222    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 7223        if self.edit_prediction_provider.is_none() || DisableAiSettings::get_global(cx).disable_ai {
 7224            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7225            self.discard_edit_prediction(false, cx);
 7226        } else {
 7227            let selection = self.selections.newest_anchor();
 7228            let cursor = selection.head();
 7229
 7230            if let Some((buffer, cursor_buffer_position)) =
 7231                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7232            {
 7233                self.edit_prediction_settings =
 7234                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7235            }
 7236        }
 7237    }
 7238
 7239    fn edit_prediction_settings_at_position(
 7240        &self,
 7241        buffer: &Entity<Buffer>,
 7242        buffer_position: language::Anchor,
 7243        cx: &App,
 7244    ) -> EditPredictionSettings {
 7245        if !self.mode.is_full()
 7246            || !self.show_edit_predictions_override.unwrap_or(true)
 7247            || self.edit_predictions_disabled_in_scope(buffer, buffer_position, cx)
 7248        {
 7249            return EditPredictionSettings::Disabled;
 7250        }
 7251
 7252        let buffer = buffer.read(cx);
 7253
 7254        let file = buffer.file();
 7255
 7256        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 7257            return EditPredictionSettings::Disabled;
 7258        };
 7259
 7260        let by_provider = matches!(
 7261            self.menu_edit_predictions_policy,
 7262            MenuEditPredictionsPolicy::ByProvider
 7263        );
 7264
 7265        let show_in_menu = by_provider
 7266            && self
 7267                .edit_prediction_provider
 7268                .as_ref()
 7269                .is_some_and(|provider| provider.provider.show_completions_in_menu());
 7270
 7271        let preview_requires_modifier =
 7272            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 7273
 7274        EditPredictionSettings::Enabled {
 7275            show_in_menu,
 7276            preview_requires_modifier,
 7277        }
 7278    }
 7279
 7280    fn should_show_edit_predictions(&self) -> bool {
 7281        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 7282    }
 7283
 7284    pub fn edit_prediction_preview_is_active(&self) -> bool {
 7285        matches!(
 7286            self.edit_prediction_preview,
 7287            EditPredictionPreview::Active { .. }
 7288        )
 7289    }
 7290
 7291    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 7292        let cursor = self.selections.newest_anchor().head();
 7293        if let Some((buffer, cursor_position)) =
 7294            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7295        {
 7296            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 7297        } else {
 7298            false
 7299        }
 7300    }
 7301
 7302    pub fn supports_minimap(&self, cx: &App) -> bool {
 7303        !self.minimap_visibility.disabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton
 7304    }
 7305
 7306    fn edit_predictions_enabled_in_buffer(
 7307        &self,
 7308        buffer: &Entity<Buffer>,
 7309        buffer_position: language::Anchor,
 7310        cx: &App,
 7311    ) -> bool {
 7312        maybe!({
 7313            if self.read_only(cx) {
 7314                return Some(false);
 7315            }
 7316            let provider = self.edit_prediction_provider()?;
 7317            if !provider.is_enabled(buffer, buffer_position, cx) {
 7318                return Some(false);
 7319            }
 7320            let buffer = buffer.read(cx);
 7321            let Some(file) = buffer.file() else {
 7322                return Some(true);
 7323            };
 7324            let settings = all_language_settings(Some(file), cx);
 7325            Some(settings.edit_predictions_enabled_for_file(file, cx))
 7326        })
 7327        .unwrap_or(false)
 7328    }
 7329
 7330    fn cycle_edit_prediction(
 7331        &mut self,
 7332        direction: Direction,
 7333        window: &mut Window,
 7334        cx: &mut Context<Self>,
 7335    ) -> Option<()> {
 7336        let provider = self.edit_prediction_provider()?;
 7337        let cursor = self.selections.newest_anchor().head();
 7338        let (buffer, cursor_buffer_position) =
 7339            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7340        if self.edit_predictions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 7341            return None;
 7342        }
 7343
 7344        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 7345        self.update_visible_edit_prediction(window, cx);
 7346
 7347        Some(())
 7348    }
 7349
 7350    pub fn show_edit_prediction(
 7351        &mut self,
 7352        _: &ShowEditPrediction,
 7353        window: &mut Window,
 7354        cx: &mut Context<Self>,
 7355    ) {
 7356        if !self.has_active_edit_prediction() {
 7357            self.refresh_edit_prediction(false, true, window, cx);
 7358            return;
 7359        }
 7360
 7361        self.update_visible_edit_prediction(window, cx);
 7362    }
 7363
 7364    pub fn display_cursor_names(
 7365        &mut self,
 7366        _: &DisplayCursorNames,
 7367        window: &mut Window,
 7368        cx: &mut Context<Self>,
 7369    ) {
 7370        self.show_cursor_names(window, cx);
 7371    }
 7372
 7373    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7374        self.show_cursor_names = true;
 7375        cx.notify();
 7376        cx.spawn_in(window, async move |this, cx| {
 7377            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 7378            this.update(cx, |this, cx| {
 7379                this.show_cursor_names = false;
 7380                cx.notify()
 7381            })
 7382            .ok()
 7383        })
 7384        .detach();
 7385    }
 7386
 7387    pub fn next_edit_prediction(
 7388        &mut self,
 7389        _: &NextEditPrediction,
 7390        window: &mut Window,
 7391        cx: &mut Context<Self>,
 7392    ) {
 7393        if self.has_active_edit_prediction() {
 7394            self.cycle_edit_prediction(Direction::Next, window, cx);
 7395        } else {
 7396            let is_copilot_disabled = self
 7397                .refresh_edit_prediction(false, true, window, cx)
 7398                .is_none();
 7399            if is_copilot_disabled {
 7400                cx.propagate();
 7401            }
 7402        }
 7403    }
 7404
 7405    pub fn previous_edit_prediction(
 7406        &mut self,
 7407        _: &PreviousEditPrediction,
 7408        window: &mut Window,
 7409        cx: &mut Context<Self>,
 7410    ) {
 7411        if self.has_active_edit_prediction() {
 7412            self.cycle_edit_prediction(Direction::Prev, window, cx);
 7413        } else {
 7414            let is_copilot_disabled = self
 7415                .refresh_edit_prediction(false, true, window, cx)
 7416                .is_none();
 7417            if is_copilot_disabled {
 7418                cx.propagate();
 7419            }
 7420        }
 7421    }
 7422
 7423    pub fn accept_edit_prediction(
 7424        &mut self,
 7425        _: &AcceptEditPrediction,
 7426        window: &mut Window,
 7427        cx: &mut Context<Self>,
 7428    ) {
 7429        if self.show_edit_predictions_in_menu() {
 7430            self.hide_context_menu(window, cx);
 7431        }
 7432
 7433        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7434            return;
 7435        };
 7436
 7437        match &active_edit_prediction.completion {
 7438            EditPrediction::MoveWithin { target, .. } => {
 7439                let target = *target;
 7440
 7441                if let Some(position_map) = &self.last_position_map {
 7442                    if position_map
 7443                        .visible_row_range
 7444                        .contains(&target.to_display_point(&position_map.snapshot).row())
 7445                        || !self.edit_prediction_requires_modifier()
 7446                    {
 7447                        self.unfold_ranges(&[target..target], true, false, cx);
 7448                        // Note that this is also done in vim's handler of the Tab action.
 7449                        self.change_selections(
 7450                            SelectionEffects::scroll(Autoscroll::newest()),
 7451                            window,
 7452                            cx,
 7453                            |selections| {
 7454                                selections.select_anchor_ranges([target..target]);
 7455                            },
 7456                        );
 7457                        self.clear_row_highlights::<EditPredictionPreview>();
 7458
 7459                        self.edit_prediction_preview
 7460                            .set_previous_scroll_position(None);
 7461                    } else {
 7462                        self.edit_prediction_preview
 7463                            .set_previous_scroll_position(Some(
 7464                                position_map.snapshot.scroll_anchor,
 7465                            ));
 7466
 7467                        self.highlight_rows::<EditPredictionPreview>(
 7468                            target..target,
 7469                            cx.theme().colors().editor_highlighted_line_background,
 7470                            RowHighlightOptions {
 7471                                autoscroll: true,
 7472                                ..Default::default()
 7473                            },
 7474                            cx,
 7475                        );
 7476                        self.request_autoscroll(Autoscroll::fit(), cx);
 7477                    }
 7478                }
 7479            }
 7480            EditPrediction::MoveOutside { snapshot, target } => {
 7481                if let Some(workspace) = self.workspace() {
 7482                    Self::open_editor_at_anchor(snapshot, *target, &workspace, window, cx)
 7483                        .detach_and_log_err(cx);
 7484                }
 7485            }
 7486            EditPrediction::Edit { edits, .. } => {
 7487                self.report_edit_prediction_event(
 7488                    active_edit_prediction.completion_id.clone(),
 7489                    true,
 7490                    cx,
 7491                );
 7492
 7493                if let Some(provider) = self.edit_prediction_provider() {
 7494                    provider.accept(cx);
 7495                }
 7496
 7497                // Store the transaction ID and selections before applying the edit
 7498                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 7499
 7500                let snapshot = self.buffer.read(cx).snapshot(cx);
 7501                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 7502
 7503                self.buffer.update(cx, |buffer, cx| {
 7504                    buffer.edit(edits.iter().cloned(), None, cx)
 7505                });
 7506
 7507                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 7508                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 7509                });
 7510
 7511                let selections = self.selections.disjoint_anchors_arc();
 7512                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 7513                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 7514                    if has_new_transaction {
 7515                        self.selection_history
 7516                            .insert_transaction(transaction_id_now, selections);
 7517                    }
 7518                }
 7519
 7520                self.update_visible_edit_prediction(window, cx);
 7521                if self.active_edit_prediction.is_none() {
 7522                    self.refresh_edit_prediction(true, true, window, cx);
 7523                }
 7524
 7525                cx.notify();
 7526            }
 7527        }
 7528
 7529        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 7530    }
 7531
 7532    pub fn accept_partial_edit_prediction(
 7533        &mut self,
 7534        _: &AcceptPartialEditPrediction,
 7535        window: &mut Window,
 7536        cx: &mut Context<Self>,
 7537    ) {
 7538        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7539            return;
 7540        };
 7541        if self.selections.count() != 1 {
 7542            return;
 7543        }
 7544
 7545        match &active_edit_prediction.completion {
 7546            EditPrediction::MoveWithin { target, .. } => {
 7547                let target = *target;
 7548                self.change_selections(
 7549                    SelectionEffects::scroll(Autoscroll::newest()),
 7550                    window,
 7551                    cx,
 7552                    |selections| {
 7553                        selections.select_anchor_ranges([target..target]);
 7554                    },
 7555                );
 7556            }
 7557            EditPrediction::MoveOutside { snapshot, target } => {
 7558                if let Some(workspace) = self.workspace() {
 7559                    Self::open_editor_at_anchor(snapshot, *target, &workspace, window, cx)
 7560                        .detach_and_log_err(cx);
 7561                }
 7562            }
 7563            EditPrediction::Edit { edits, .. } => {
 7564                self.report_edit_prediction_event(
 7565                    active_edit_prediction.completion_id.clone(),
 7566                    true,
 7567                    cx,
 7568                );
 7569
 7570                // Find an insertion that starts at the cursor position.
 7571                let snapshot = self.buffer.read(cx).snapshot(cx);
 7572                let cursor_offset = self
 7573                    .selections
 7574                    .newest::<usize>(&self.display_snapshot(cx))
 7575                    .head();
 7576                let insertion = edits.iter().find_map(|(range, text)| {
 7577                    let range = range.to_offset(&snapshot);
 7578                    if range.is_empty() && range.start == cursor_offset {
 7579                        Some(text)
 7580                    } else {
 7581                        None
 7582                    }
 7583                });
 7584
 7585                if let Some(text) = insertion {
 7586                    let mut partial_completion = text
 7587                        .chars()
 7588                        .by_ref()
 7589                        .take_while(|c| c.is_alphabetic())
 7590                        .collect::<String>();
 7591                    if partial_completion.is_empty() {
 7592                        partial_completion = text
 7593                            .chars()
 7594                            .by_ref()
 7595                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7596                            .collect::<String>();
 7597                    }
 7598
 7599                    cx.emit(EditorEvent::InputHandled {
 7600                        utf16_range_to_replace: None,
 7601                        text: partial_completion.clone().into(),
 7602                    });
 7603
 7604                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 7605
 7606                    self.refresh_edit_prediction(true, true, window, cx);
 7607                    cx.notify();
 7608                } else {
 7609                    self.accept_edit_prediction(&Default::default(), window, cx);
 7610                }
 7611            }
 7612        }
 7613    }
 7614
 7615    fn discard_edit_prediction(
 7616        &mut self,
 7617        should_report_edit_prediction_event: bool,
 7618        cx: &mut Context<Self>,
 7619    ) -> bool {
 7620        if should_report_edit_prediction_event {
 7621            let completion_id = self
 7622                .active_edit_prediction
 7623                .as_ref()
 7624                .and_then(|active_completion| active_completion.completion_id.clone());
 7625
 7626            self.report_edit_prediction_event(completion_id, false, cx);
 7627        }
 7628
 7629        if let Some(provider) = self.edit_prediction_provider() {
 7630            provider.discard(cx);
 7631        }
 7632
 7633        self.take_active_edit_prediction(cx)
 7634    }
 7635
 7636    fn report_edit_prediction_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7637        let Some(provider) = self.edit_prediction_provider() else {
 7638            return;
 7639        };
 7640
 7641        let Some((_, buffer, _)) = self
 7642            .buffer
 7643            .read(cx)
 7644            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7645        else {
 7646            return;
 7647        };
 7648
 7649        let extension = buffer
 7650            .read(cx)
 7651            .file()
 7652            .and_then(|file| Some(file.path().extension()?.to_string()));
 7653
 7654        let event_type = match accepted {
 7655            true => "Edit Prediction Accepted",
 7656            false => "Edit Prediction Discarded",
 7657        };
 7658        telemetry::event!(
 7659            event_type,
 7660            provider = provider.name(),
 7661            prediction_id = id,
 7662            suggestion_accepted = accepted,
 7663            file_extension = extension,
 7664        );
 7665    }
 7666
 7667    fn open_editor_at_anchor(
 7668        snapshot: &language::BufferSnapshot,
 7669        target: language::Anchor,
 7670        workspace: &Entity<Workspace>,
 7671        window: &mut Window,
 7672        cx: &mut App,
 7673    ) -> Task<Result<()>> {
 7674        workspace.update(cx, |workspace, cx| {
 7675            let path = snapshot.file().map(|file| file.full_path(cx));
 7676            let Some(path) =
 7677                path.and_then(|path| workspace.project().read(cx).find_project_path(path, cx))
 7678            else {
 7679                return Task::ready(Err(anyhow::anyhow!("Project path not found")));
 7680            };
 7681            let target = text::ToPoint::to_point(&target, snapshot);
 7682            let item = workspace.open_path(path, None, true, window, cx);
 7683            window.spawn(cx, async move |cx| {
 7684                let Some(editor) = item.await?.downcast::<Editor>() else {
 7685                    return Ok(());
 7686                };
 7687                editor
 7688                    .update_in(cx, |editor, window, cx| {
 7689                        editor.go_to_singleton_buffer_point(target, window, cx);
 7690                    })
 7691                    .ok();
 7692                anyhow::Ok(())
 7693            })
 7694        })
 7695    }
 7696
 7697    pub fn has_active_edit_prediction(&self) -> bool {
 7698        self.active_edit_prediction.is_some()
 7699    }
 7700
 7701    fn take_active_edit_prediction(&mut self, cx: &mut Context<Self>) -> bool {
 7702        let Some(active_edit_prediction) = self.active_edit_prediction.take() else {
 7703            return false;
 7704        };
 7705
 7706        self.splice_inlays(&active_edit_prediction.inlay_ids, Default::default(), cx);
 7707        self.clear_highlights::<EditPredictionHighlight>(cx);
 7708        self.stale_edit_prediction_in_menu = Some(active_edit_prediction);
 7709        true
 7710    }
 7711
 7712    /// Returns true when we're displaying the edit prediction popover below the cursor
 7713    /// like we are not previewing and the LSP autocomplete menu is visible
 7714    /// or we are in `when_holding_modifier` mode.
 7715    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7716        if self.edit_prediction_preview_is_active()
 7717            || !self.show_edit_predictions_in_menu()
 7718            || !self.edit_predictions_enabled()
 7719        {
 7720            return false;
 7721        }
 7722
 7723        if self.has_visible_completions_menu() {
 7724            return true;
 7725        }
 7726
 7727        has_completion && self.edit_prediction_requires_modifier()
 7728    }
 7729
 7730    fn handle_modifiers_changed(
 7731        &mut self,
 7732        modifiers: Modifiers,
 7733        position_map: &PositionMap,
 7734        window: &mut Window,
 7735        cx: &mut Context<Self>,
 7736    ) {
 7737        // Ensure that the edit prediction preview is updated, even when not
 7738        // enabled, if there's an active edit prediction preview.
 7739        if self.show_edit_predictions_in_menu()
 7740            || matches!(
 7741                self.edit_prediction_preview,
 7742                EditPredictionPreview::Active { .. }
 7743            )
 7744        {
 7745            self.update_edit_prediction_preview(&modifiers, window, cx);
 7746        }
 7747
 7748        self.update_selection_mode(&modifiers, position_map, window, cx);
 7749
 7750        let mouse_position = window.mouse_position();
 7751        if !position_map.text_hitbox.is_hovered(window) {
 7752            return;
 7753        }
 7754
 7755        self.update_hovered_link(
 7756            position_map.point_for_position(mouse_position),
 7757            &position_map.snapshot,
 7758            modifiers,
 7759            window,
 7760            cx,
 7761        )
 7762    }
 7763
 7764    fn is_cmd_or_ctrl_pressed(modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7765        match EditorSettings::get_global(cx).multi_cursor_modifier {
 7766            MultiCursorModifier::Alt => modifiers.secondary(),
 7767            MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 7768        }
 7769    }
 7770
 7771    fn is_alt_pressed(modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7772        match EditorSettings::get_global(cx).multi_cursor_modifier {
 7773            MultiCursorModifier::Alt => modifiers.alt,
 7774            MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 7775        }
 7776    }
 7777
 7778    fn columnar_selection_mode(
 7779        modifiers: &Modifiers,
 7780        cx: &mut Context<Self>,
 7781    ) -> Option<ColumnarMode> {
 7782        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 7783            if Self::is_cmd_or_ctrl_pressed(modifiers, cx) {
 7784                Some(ColumnarMode::FromMouse)
 7785            } else if Self::is_alt_pressed(modifiers, cx) {
 7786                Some(ColumnarMode::FromSelection)
 7787            } else {
 7788                None
 7789            }
 7790        } else {
 7791            None
 7792        }
 7793    }
 7794
 7795    fn update_selection_mode(
 7796        &mut self,
 7797        modifiers: &Modifiers,
 7798        position_map: &PositionMap,
 7799        window: &mut Window,
 7800        cx: &mut Context<Self>,
 7801    ) {
 7802        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 7803            return;
 7804        };
 7805        if self.selections.pending_anchor().is_none() {
 7806            return;
 7807        }
 7808
 7809        let mouse_position = window.mouse_position();
 7810        let point_for_position = position_map.point_for_position(mouse_position);
 7811        let position = point_for_position.previous_valid;
 7812
 7813        self.select(
 7814            SelectPhase::BeginColumnar {
 7815                position,
 7816                reset: false,
 7817                mode,
 7818                goal_column: point_for_position.exact_unclipped.column(),
 7819            },
 7820            window,
 7821            cx,
 7822        );
 7823    }
 7824
 7825    fn update_edit_prediction_preview(
 7826        &mut self,
 7827        modifiers: &Modifiers,
 7828        window: &mut Window,
 7829        cx: &mut Context<Self>,
 7830    ) {
 7831        let mut modifiers_held = false;
 7832        if let Some(accept_keystroke) = self
 7833            .accept_edit_prediction_keybind(false, window, cx)
 7834            .keystroke()
 7835        {
 7836            modifiers_held = modifiers_held
 7837                || (accept_keystroke.modifiers() == modifiers
 7838                    && accept_keystroke.modifiers().modified());
 7839        };
 7840        if let Some(accept_partial_keystroke) = self
 7841            .accept_edit_prediction_keybind(true, window, cx)
 7842            .keystroke()
 7843        {
 7844            modifiers_held = modifiers_held
 7845                || (accept_partial_keystroke.modifiers() == modifiers
 7846                    && accept_partial_keystroke.modifiers().modified());
 7847        }
 7848
 7849        if modifiers_held {
 7850            if matches!(
 7851                self.edit_prediction_preview,
 7852                EditPredictionPreview::Inactive { .. }
 7853            ) {
 7854                self.edit_prediction_preview = EditPredictionPreview::Active {
 7855                    previous_scroll_position: None,
 7856                    since: Instant::now(),
 7857                };
 7858
 7859                self.update_visible_edit_prediction(window, cx);
 7860                cx.notify();
 7861            }
 7862        } else if let EditPredictionPreview::Active {
 7863            previous_scroll_position,
 7864            since,
 7865        } = self.edit_prediction_preview
 7866        {
 7867            if let (Some(previous_scroll_position), Some(position_map)) =
 7868                (previous_scroll_position, self.last_position_map.as_ref())
 7869            {
 7870                self.set_scroll_position(
 7871                    previous_scroll_position
 7872                        .scroll_position(&position_map.snapshot.display_snapshot),
 7873                    window,
 7874                    cx,
 7875                );
 7876            }
 7877
 7878            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 7879                released_too_fast: since.elapsed() < Duration::from_millis(200),
 7880            };
 7881            self.clear_row_highlights::<EditPredictionPreview>();
 7882            self.update_visible_edit_prediction(window, cx);
 7883            cx.notify();
 7884        }
 7885    }
 7886
 7887    fn update_visible_edit_prediction(
 7888        &mut self,
 7889        _window: &mut Window,
 7890        cx: &mut Context<Self>,
 7891    ) -> Option<()> {
 7892        if DisableAiSettings::get_global(cx).disable_ai {
 7893            return None;
 7894        }
 7895
 7896        if self.ime_transaction.is_some() {
 7897            self.discard_edit_prediction(false, cx);
 7898            return None;
 7899        }
 7900
 7901        let selection = self.selections.newest_anchor();
 7902        let cursor = selection.head();
 7903        let multibuffer = self.buffer.read(cx).snapshot(cx);
 7904        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 7905        let excerpt_id = cursor.excerpt_id;
 7906
 7907        let show_in_menu = self.show_edit_predictions_in_menu();
 7908        let completions_menu_has_precedence = !show_in_menu
 7909            && (self.context_menu.borrow().is_some()
 7910                || (!self.completion_tasks.is_empty() && !self.has_active_edit_prediction()));
 7911
 7912        if completions_menu_has_precedence
 7913            || !offset_selection.is_empty()
 7914            || self
 7915                .active_edit_prediction
 7916                .as_ref()
 7917                .is_some_and(|completion| {
 7918                    let Some(invalidation_range) = completion.invalidation_range.as_ref() else {
 7919                        return false;
 7920                    };
 7921                    let invalidation_range = invalidation_range.to_offset(&multibuffer);
 7922                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 7923                    !invalidation_range.contains(&offset_selection.head())
 7924                })
 7925        {
 7926            self.discard_edit_prediction(false, cx);
 7927            return None;
 7928        }
 7929
 7930        self.take_active_edit_prediction(cx);
 7931        let Some(provider) = self.edit_prediction_provider() else {
 7932            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7933            return None;
 7934        };
 7935
 7936        let (buffer, cursor_buffer_position) =
 7937            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7938
 7939        self.edit_prediction_settings =
 7940            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7941
 7942        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 7943
 7944        if self.edit_prediction_indent_conflict {
 7945            let cursor_point = cursor.to_point(&multibuffer);
 7946
 7947            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 7948
 7949            if let Some((_, indent)) = indents.iter().next()
 7950                && indent.len == cursor_point.column
 7951            {
 7952                self.edit_prediction_indent_conflict = false;
 7953            }
 7954        }
 7955
 7956        let edit_prediction = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 7957
 7958        let (completion_id, edits, edit_preview) = match edit_prediction {
 7959            edit_prediction::EditPrediction::Local {
 7960                id,
 7961                edits,
 7962                edit_preview,
 7963            } => (id, edits, edit_preview),
 7964            edit_prediction::EditPrediction::Jump {
 7965                id,
 7966                snapshot,
 7967                target,
 7968            } => {
 7969                self.stale_edit_prediction_in_menu = None;
 7970                self.active_edit_prediction = Some(EditPredictionState {
 7971                    inlay_ids: vec![],
 7972                    completion: EditPrediction::MoveOutside { snapshot, target },
 7973                    completion_id: id,
 7974                    invalidation_range: None,
 7975                });
 7976                cx.notify();
 7977                return Some(());
 7978            }
 7979        };
 7980
 7981        let edits = edits
 7982            .into_iter()
 7983            .flat_map(|(range, new_text)| {
 7984                Some((
 7985                    multibuffer.anchor_range_in_excerpt(excerpt_id, range)?,
 7986                    new_text,
 7987                ))
 7988            })
 7989            .collect::<Vec<_>>();
 7990        if edits.is_empty() {
 7991            return None;
 7992        }
 7993
 7994        let first_edit_start = edits.first().unwrap().0.start;
 7995        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 7996        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 7997
 7998        let last_edit_end = edits.last().unwrap().0.end;
 7999        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 8000        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 8001
 8002        let cursor_row = cursor.to_point(&multibuffer).row;
 8003
 8004        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 8005
 8006        let mut inlay_ids = Vec::new();
 8007        let invalidation_row_range;
 8008        let move_invalidation_row_range = if cursor_row < edit_start_row {
 8009            Some(cursor_row..edit_end_row)
 8010        } else if cursor_row > edit_end_row {
 8011            Some(edit_start_row..cursor_row)
 8012        } else {
 8013            None
 8014        };
 8015        let supports_jump = self
 8016            .edit_prediction_provider
 8017            .as_ref()
 8018            .map(|provider| provider.provider.supports_jump_to_edit())
 8019            .unwrap_or(true);
 8020
 8021        let is_move = supports_jump
 8022            && (move_invalidation_row_range.is_some() || self.edit_predictions_hidden_for_vim_mode);
 8023        let completion = if is_move {
 8024            invalidation_row_range =
 8025                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 8026            let target = first_edit_start;
 8027            EditPrediction::MoveWithin { target, snapshot }
 8028        } else {
 8029            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 8030                && !self.edit_predictions_hidden_for_vim_mode;
 8031
 8032            if show_completions_in_buffer {
 8033                if edits
 8034                    .iter()
 8035                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 8036                {
 8037                    let mut inlays = Vec::new();
 8038                    for (range, new_text) in &edits {
 8039                        let inlay = Inlay::edit_prediction(
 8040                            post_inc(&mut self.next_inlay_id),
 8041                            range.start,
 8042                            new_text.as_ref(),
 8043                        );
 8044                        inlay_ids.push(inlay.id);
 8045                        inlays.push(inlay);
 8046                    }
 8047
 8048                    self.splice_inlays(&[], inlays, cx);
 8049                } else {
 8050                    let background_color = cx.theme().status().deleted_background;
 8051                    self.highlight_text::<EditPredictionHighlight>(
 8052                        edits.iter().map(|(range, _)| range.clone()).collect(),
 8053                        HighlightStyle {
 8054                            background_color: Some(background_color),
 8055                            ..Default::default()
 8056                        },
 8057                        cx,
 8058                    );
 8059                }
 8060            }
 8061
 8062            invalidation_row_range = edit_start_row..edit_end_row;
 8063
 8064            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 8065                if provider.show_tab_accept_marker() {
 8066                    EditDisplayMode::TabAccept
 8067                } else {
 8068                    EditDisplayMode::Inline
 8069                }
 8070            } else {
 8071                EditDisplayMode::DiffPopover
 8072            };
 8073
 8074            EditPrediction::Edit {
 8075                edits,
 8076                edit_preview,
 8077                display_mode,
 8078                snapshot,
 8079            }
 8080        };
 8081
 8082        let invalidation_range = multibuffer
 8083            .anchor_before(Point::new(invalidation_row_range.start, 0))
 8084            ..multibuffer.anchor_after(Point::new(
 8085                invalidation_row_range.end,
 8086                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 8087            ));
 8088
 8089        self.stale_edit_prediction_in_menu = None;
 8090        self.active_edit_prediction = Some(EditPredictionState {
 8091            inlay_ids,
 8092            completion,
 8093            completion_id,
 8094            invalidation_range: Some(invalidation_range),
 8095        });
 8096
 8097        cx.notify();
 8098
 8099        Some(())
 8100    }
 8101
 8102    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn EditPredictionProviderHandle>> {
 8103        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 8104    }
 8105
 8106    fn clear_tasks(&mut self) {
 8107        self.tasks.clear()
 8108    }
 8109
 8110    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 8111        if self.tasks.insert(key, value).is_some() {
 8112            // This case should hopefully be rare, but just in case...
 8113            log::error!(
 8114                "multiple different run targets found on a single line, only the last target will be rendered"
 8115            )
 8116        }
 8117    }
 8118
 8119    /// Get all display points of breakpoints that will be rendered within editor
 8120    ///
 8121    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 8122    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 8123    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 8124    fn active_breakpoints(
 8125        &self,
 8126        range: Range<DisplayRow>,
 8127        window: &mut Window,
 8128        cx: &mut Context<Self>,
 8129    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 8130        let mut breakpoint_display_points = HashMap::default();
 8131
 8132        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 8133            return breakpoint_display_points;
 8134        };
 8135
 8136        let snapshot = self.snapshot(window, cx);
 8137
 8138        let multi_buffer_snapshot = snapshot.buffer_snapshot();
 8139        let Some(project) = self.project() else {
 8140            return breakpoint_display_points;
 8141        };
 8142
 8143        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 8144            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 8145
 8146        for (buffer_snapshot, range, excerpt_id) in
 8147            multi_buffer_snapshot.range_to_buffer_ranges(range)
 8148        {
 8149            let Some(buffer) = project
 8150                .read(cx)
 8151                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 8152            else {
 8153                continue;
 8154            };
 8155            let breakpoints = breakpoint_store.read(cx).breakpoints(
 8156                &buffer,
 8157                Some(
 8158                    buffer_snapshot.anchor_before(range.start)
 8159                        ..buffer_snapshot.anchor_after(range.end),
 8160                ),
 8161                buffer_snapshot,
 8162                cx,
 8163            );
 8164            for (breakpoint, state) in breakpoints {
 8165                let multi_buffer_anchor =
 8166                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 8167                let position = multi_buffer_anchor
 8168                    .to_point(&multi_buffer_snapshot)
 8169                    .to_display_point(&snapshot);
 8170
 8171                breakpoint_display_points.insert(
 8172                    position.row(),
 8173                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 8174                );
 8175            }
 8176        }
 8177
 8178        breakpoint_display_points
 8179    }
 8180
 8181    fn breakpoint_context_menu(
 8182        &self,
 8183        anchor: Anchor,
 8184        window: &mut Window,
 8185        cx: &mut Context<Self>,
 8186    ) -> Entity<ui::ContextMenu> {
 8187        let weak_editor = cx.weak_entity();
 8188        let focus_handle = self.focus_handle(cx);
 8189
 8190        let row = self
 8191            .buffer
 8192            .read(cx)
 8193            .snapshot(cx)
 8194            .summary_for_anchor::<Point>(&anchor)
 8195            .row;
 8196
 8197        let breakpoint = self
 8198            .breakpoint_at_row(row, window, cx)
 8199            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 8200
 8201        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 8202            "Edit Log Breakpoint"
 8203        } else {
 8204            "Set Log Breakpoint"
 8205        };
 8206
 8207        let condition_breakpoint_msg = if breakpoint
 8208            .as_ref()
 8209            .is_some_and(|bp| bp.1.condition.is_some())
 8210        {
 8211            "Edit Condition Breakpoint"
 8212        } else {
 8213            "Set Condition Breakpoint"
 8214        };
 8215
 8216        let hit_condition_breakpoint_msg = if breakpoint
 8217            .as_ref()
 8218            .is_some_and(|bp| bp.1.hit_condition.is_some())
 8219        {
 8220            "Edit Hit Condition Breakpoint"
 8221        } else {
 8222            "Set Hit Condition Breakpoint"
 8223        };
 8224
 8225        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 8226            "Unset Breakpoint"
 8227        } else {
 8228            "Set Breakpoint"
 8229        };
 8230
 8231        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 8232
 8233        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 8234            BreakpointState::Enabled => Some("Disable"),
 8235            BreakpointState::Disabled => Some("Enable"),
 8236        });
 8237
 8238        let (anchor, breakpoint) =
 8239            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 8240
 8241        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 8242            menu.on_blur_subscription(Subscription::new(|| {}))
 8243                .context(focus_handle)
 8244                .when(run_to_cursor, |this| {
 8245                    let weak_editor = weak_editor.clone();
 8246                    this.entry("Run to cursor", None, move |window, cx| {
 8247                        weak_editor
 8248                            .update(cx, |editor, cx| {
 8249                                editor.change_selections(
 8250                                    SelectionEffects::no_scroll(),
 8251                                    window,
 8252                                    cx,
 8253                                    |s| s.select_ranges([Point::new(row, 0)..Point::new(row, 0)]),
 8254                                );
 8255                            })
 8256                            .ok();
 8257
 8258                        window.dispatch_action(Box::new(RunToCursor), cx);
 8259                    })
 8260                    .separator()
 8261                })
 8262                .when_some(toggle_state_msg, |this, msg| {
 8263                    this.entry(msg, None, {
 8264                        let weak_editor = weak_editor.clone();
 8265                        let breakpoint = breakpoint.clone();
 8266                        move |_window, cx| {
 8267                            weak_editor
 8268                                .update(cx, |this, cx| {
 8269                                    this.edit_breakpoint_at_anchor(
 8270                                        anchor,
 8271                                        breakpoint.as_ref().clone(),
 8272                                        BreakpointEditAction::InvertState,
 8273                                        cx,
 8274                                    );
 8275                                })
 8276                                .log_err();
 8277                        }
 8278                    })
 8279                })
 8280                .entry(set_breakpoint_msg, None, {
 8281                    let weak_editor = weak_editor.clone();
 8282                    let breakpoint = breakpoint.clone();
 8283                    move |_window, cx| {
 8284                        weak_editor
 8285                            .update(cx, |this, cx| {
 8286                                this.edit_breakpoint_at_anchor(
 8287                                    anchor,
 8288                                    breakpoint.as_ref().clone(),
 8289                                    BreakpointEditAction::Toggle,
 8290                                    cx,
 8291                                );
 8292                            })
 8293                            .log_err();
 8294                    }
 8295                })
 8296                .entry(log_breakpoint_msg, None, {
 8297                    let breakpoint = breakpoint.clone();
 8298                    let weak_editor = weak_editor.clone();
 8299                    move |window, cx| {
 8300                        weak_editor
 8301                            .update(cx, |this, cx| {
 8302                                this.add_edit_breakpoint_block(
 8303                                    anchor,
 8304                                    breakpoint.as_ref(),
 8305                                    BreakpointPromptEditAction::Log,
 8306                                    window,
 8307                                    cx,
 8308                                );
 8309                            })
 8310                            .log_err();
 8311                    }
 8312                })
 8313                .entry(condition_breakpoint_msg, None, {
 8314                    let breakpoint = breakpoint.clone();
 8315                    let weak_editor = weak_editor.clone();
 8316                    move |window, cx| {
 8317                        weak_editor
 8318                            .update(cx, |this, cx| {
 8319                                this.add_edit_breakpoint_block(
 8320                                    anchor,
 8321                                    breakpoint.as_ref(),
 8322                                    BreakpointPromptEditAction::Condition,
 8323                                    window,
 8324                                    cx,
 8325                                );
 8326                            })
 8327                            .log_err();
 8328                    }
 8329                })
 8330                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 8331                    weak_editor
 8332                        .update(cx, |this, cx| {
 8333                            this.add_edit_breakpoint_block(
 8334                                anchor,
 8335                                breakpoint.as_ref(),
 8336                                BreakpointPromptEditAction::HitCondition,
 8337                                window,
 8338                                cx,
 8339                            );
 8340                        })
 8341                        .log_err();
 8342                })
 8343        })
 8344    }
 8345
 8346    fn render_breakpoint(
 8347        &self,
 8348        position: Anchor,
 8349        row: DisplayRow,
 8350        breakpoint: &Breakpoint,
 8351        state: Option<BreakpointSessionState>,
 8352        cx: &mut Context<Self>,
 8353    ) -> IconButton {
 8354        let is_rejected = state.is_some_and(|s| !s.verified);
 8355        // Is it a breakpoint that shows up when hovering over gutter?
 8356        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 8357            (false, false),
 8358            |PhantomBreakpointIndicator {
 8359                 is_active,
 8360                 display_row,
 8361                 collides_with_existing_breakpoint,
 8362             }| {
 8363                (
 8364                    is_active && display_row == row,
 8365                    collides_with_existing_breakpoint,
 8366                )
 8367            },
 8368        );
 8369
 8370        let (color, icon) = {
 8371            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 8372                (false, false) => ui::IconName::DebugBreakpoint,
 8373                (true, false) => ui::IconName::DebugLogBreakpoint,
 8374                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 8375                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 8376            };
 8377
 8378            let color = if is_phantom {
 8379                Color::Hint
 8380            } else if is_rejected {
 8381                Color::Disabled
 8382            } else {
 8383                Color::Debugger
 8384            };
 8385
 8386            (color, icon)
 8387        };
 8388
 8389        let breakpoint = Arc::from(breakpoint.clone());
 8390
 8391        let alt_as_text = gpui::Keystroke {
 8392            modifiers: Modifiers::secondary_key(),
 8393            ..Default::default()
 8394        };
 8395        let primary_action_text = if breakpoint.is_disabled() {
 8396            "Enable breakpoint"
 8397        } else if is_phantom && !collides_with_existing {
 8398            "Set breakpoint"
 8399        } else {
 8400            "Unset breakpoint"
 8401        };
 8402        let focus_handle = self.focus_handle.clone();
 8403
 8404        let meta = if is_rejected {
 8405            SharedString::from("No executable code is associated with this line.")
 8406        } else if collides_with_existing && !breakpoint.is_disabled() {
 8407            SharedString::from(format!(
 8408                "{alt_as_text}-click to disable,\nright-click for more options."
 8409            ))
 8410        } else {
 8411            SharedString::from("Right-click for more options.")
 8412        };
 8413        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 8414            .icon_size(IconSize::XSmall)
 8415            .size(ui::ButtonSize::None)
 8416            .when(is_rejected, |this| {
 8417                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 8418            })
 8419            .icon_color(color)
 8420            .style(ButtonStyle::Transparent)
 8421            .on_click(cx.listener({
 8422                move |editor, event: &ClickEvent, window, cx| {
 8423                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 8424                        BreakpointEditAction::InvertState
 8425                    } else {
 8426                        BreakpointEditAction::Toggle
 8427                    };
 8428
 8429                    window.focus(&editor.focus_handle(cx));
 8430                    editor.edit_breakpoint_at_anchor(
 8431                        position,
 8432                        breakpoint.as_ref().clone(),
 8433                        edit_action,
 8434                        cx,
 8435                    );
 8436                }
 8437            }))
 8438            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8439                editor.set_breakpoint_context_menu(
 8440                    row,
 8441                    Some(position),
 8442                    event.position(),
 8443                    window,
 8444                    cx,
 8445                );
 8446            }))
 8447            .tooltip(move |_window, cx| {
 8448                Tooltip::with_meta_in(
 8449                    primary_action_text,
 8450                    Some(&ToggleBreakpoint),
 8451                    meta.clone(),
 8452                    &focus_handle,
 8453                    cx,
 8454                )
 8455            })
 8456    }
 8457
 8458    fn build_tasks_context(
 8459        project: &Entity<Project>,
 8460        buffer: &Entity<Buffer>,
 8461        buffer_row: u32,
 8462        tasks: &Arc<RunnableTasks>,
 8463        cx: &mut Context<Self>,
 8464    ) -> Task<Option<task::TaskContext>> {
 8465        let position = Point::new(buffer_row, tasks.column);
 8466        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 8467        let location = Location {
 8468            buffer: buffer.clone(),
 8469            range: range_start..range_start,
 8470        };
 8471        // Fill in the environmental variables from the tree-sitter captures
 8472        let mut captured_task_variables = TaskVariables::default();
 8473        for (capture_name, value) in tasks.extra_variables.clone() {
 8474            captured_task_variables.insert(
 8475                task::VariableName::Custom(capture_name.into()),
 8476                value.clone(),
 8477            );
 8478        }
 8479        project.update(cx, |project, cx| {
 8480            project.task_store().update(cx, |task_store, cx| {
 8481                task_store.task_context_for_location(captured_task_variables, location, cx)
 8482            })
 8483        })
 8484    }
 8485
 8486    pub fn spawn_nearest_task(
 8487        &mut self,
 8488        action: &SpawnNearestTask,
 8489        window: &mut Window,
 8490        cx: &mut Context<Self>,
 8491    ) {
 8492        let Some((workspace, _)) = self.workspace.clone() else {
 8493            return;
 8494        };
 8495        let Some(project) = self.project.clone() else {
 8496            return;
 8497        };
 8498
 8499        // Try to find a closest, enclosing node using tree-sitter that has a task
 8500        let Some((buffer, buffer_row, tasks)) = self
 8501            .find_enclosing_node_task(cx)
 8502            // Or find the task that's closest in row-distance.
 8503            .or_else(|| self.find_closest_task(cx))
 8504        else {
 8505            return;
 8506        };
 8507
 8508        let reveal_strategy = action.reveal;
 8509        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 8510        cx.spawn_in(window, async move |_, cx| {
 8511            let context = task_context.await?;
 8512            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 8513
 8514            let resolved = &mut resolved_task.resolved;
 8515            resolved.reveal = reveal_strategy;
 8516
 8517            workspace
 8518                .update_in(cx, |workspace, window, cx| {
 8519                    workspace.schedule_resolved_task(
 8520                        task_source_kind,
 8521                        resolved_task,
 8522                        false,
 8523                        window,
 8524                        cx,
 8525                    );
 8526                })
 8527                .ok()
 8528        })
 8529        .detach();
 8530    }
 8531
 8532    fn find_closest_task(
 8533        &mut self,
 8534        cx: &mut Context<Self>,
 8535    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8536        let cursor_row = self
 8537            .selections
 8538            .newest_adjusted(&self.display_snapshot(cx))
 8539            .head()
 8540            .row;
 8541
 8542        let ((buffer_id, row), tasks) = self
 8543            .tasks
 8544            .iter()
 8545            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 8546
 8547        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 8548        let tasks = Arc::new(tasks.to_owned());
 8549        Some((buffer, *row, tasks))
 8550    }
 8551
 8552    fn find_enclosing_node_task(
 8553        &mut self,
 8554        cx: &mut Context<Self>,
 8555    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8556        let snapshot = self.buffer.read(cx).snapshot(cx);
 8557        let offset = self
 8558            .selections
 8559            .newest::<usize>(&self.display_snapshot(cx))
 8560            .head();
 8561        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 8562        let buffer_id = excerpt.buffer().remote_id();
 8563
 8564        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 8565        let mut cursor = layer.node().walk();
 8566
 8567        while cursor.goto_first_child_for_byte(offset).is_some() {
 8568            if cursor.node().end_byte() == offset {
 8569                cursor.goto_next_sibling();
 8570            }
 8571        }
 8572
 8573        // Ascend to the smallest ancestor that contains the range and has a task.
 8574        loop {
 8575            let node = cursor.node();
 8576            let node_range = node.byte_range();
 8577            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 8578
 8579            // Check if this node contains our offset
 8580            if node_range.start <= offset && node_range.end >= offset {
 8581                // If it contains offset, check for task
 8582                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 8583                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 8584                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 8585                }
 8586            }
 8587
 8588            if !cursor.goto_parent() {
 8589                break;
 8590            }
 8591        }
 8592        None
 8593    }
 8594
 8595    fn render_run_indicator(
 8596        &self,
 8597        _style: &EditorStyle,
 8598        is_active: bool,
 8599        row: DisplayRow,
 8600        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 8601        cx: &mut Context<Self>,
 8602    ) -> IconButton {
 8603        let color = Color::Muted;
 8604        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 8605
 8606        IconButton::new(
 8607            ("run_indicator", row.0 as usize),
 8608            ui::IconName::PlayOutlined,
 8609        )
 8610        .shape(ui::IconButtonShape::Square)
 8611        .icon_size(IconSize::XSmall)
 8612        .icon_color(color)
 8613        .toggle_state(is_active)
 8614        .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 8615            let quick_launch = match e {
 8616                ClickEvent::Keyboard(_) => true,
 8617                ClickEvent::Mouse(e) => e.down.button == MouseButton::Left,
 8618            };
 8619
 8620            window.focus(&editor.focus_handle(cx));
 8621            editor.toggle_code_actions(
 8622                &ToggleCodeActions {
 8623                    deployed_from: Some(CodeActionSource::RunMenu(row)),
 8624                    quick_launch,
 8625                },
 8626                window,
 8627                cx,
 8628            );
 8629        }))
 8630        .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8631            editor.set_breakpoint_context_menu(row, position, event.position(), window, cx);
 8632        }))
 8633    }
 8634
 8635    pub fn context_menu_visible(&self) -> bool {
 8636        !self.edit_prediction_preview_is_active()
 8637            && self
 8638                .context_menu
 8639                .borrow()
 8640                .as_ref()
 8641                .is_some_and(|menu| menu.visible())
 8642    }
 8643
 8644    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 8645        self.context_menu
 8646            .borrow()
 8647            .as_ref()
 8648            .map(|menu| menu.origin())
 8649    }
 8650
 8651    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 8652        self.context_menu_options = Some(options);
 8653    }
 8654
 8655    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = px(24.);
 8656    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = px(2.);
 8657
 8658    fn render_edit_prediction_popover(
 8659        &mut self,
 8660        text_bounds: &Bounds<Pixels>,
 8661        content_origin: gpui::Point<Pixels>,
 8662        right_margin: Pixels,
 8663        editor_snapshot: &EditorSnapshot,
 8664        visible_row_range: Range<DisplayRow>,
 8665        scroll_top: ScrollOffset,
 8666        scroll_bottom: ScrollOffset,
 8667        line_layouts: &[LineWithInvisibles],
 8668        line_height: Pixels,
 8669        scroll_position: gpui::Point<ScrollOffset>,
 8670        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8671        newest_selection_head: Option<DisplayPoint>,
 8672        editor_width: Pixels,
 8673        style: &EditorStyle,
 8674        window: &mut Window,
 8675        cx: &mut App,
 8676    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8677        if self.mode().is_minimap() {
 8678            return None;
 8679        }
 8680        let active_edit_prediction = self.active_edit_prediction.as_ref()?;
 8681
 8682        if self.edit_prediction_visible_in_cursor_popover(true) {
 8683            return None;
 8684        }
 8685
 8686        match &active_edit_prediction.completion {
 8687            EditPrediction::MoveWithin { target, .. } => {
 8688                let target_display_point = target.to_display_point(editor_snapshot);
 8689
 8690                if self.edit_prediction_requires_modifier() {
 8691                    if !self.edit_prediction_preview_is_active() {
 8692                        return None;
 8693                    }
 8694
 8695                    self.render_edit_prediction_modifier_jump_popover(
 8696                        text_bounds,
 8697                        content_origin,
 8698                        visible_row_range,
 8699                        line_layouts,
 8700                        line_height,
 8701                        scroll_pixel_position,
 8702                        newest_selection_head,
 8703                        target_display_point,
 8704                        window,
 8705                        cx,
 8706                    )
 8707                } else {
 8708                    self.render_edit_prediction_eager_jump_popover(
 8709                        text_bounds,
 8710                        content_origin,
 8711                        editor_snapshot,
 8712                        visible_row_range,
 8713                        scroll_top,
 8714                        scroll_bottom,
 8715                        line_height,
 8716                        scroll_pixel_position,
 8717                        target_display_point,
 8718                        editor_width,
 8719                        window,
 8720                        cx,
 8721                    )
 8722                }
 8723            }
 8724            EditPrediction::Edit {
 8725                display_mode: EditDisplayMode::Inline,
 8726                ..
 8727            } => None,
 8728            EditPrediction::Edit {
 8729                display_mode: EditDisplayMode::TabAccept,
 8730                edits,
 8731                ..
 8732            } => {
 8733                let range = &edits.first()?.0;
 8734                let target_display_point = range.end.to_display_point(editor_snapshot);
 8735
 8736                self.render_edit_prediction_end_of_line_popover(
 8737                    "Accept",
 8738                    editor_snapshot,
 8739                    visible_row_range,
 8740                    target_display_point,
 8741                    line_height,
 8742                    scroll_pixel_position,
 8743                    content_origin,
 8744                    editor_width,
 8745                    window,
 8746                    cx,
 8747                )
 8748            }
 8749            EditPrediction::Edit {
 8750                edits,
 8751                edit_preview,
 8752                display_mode: EditDisplayMode::DiffPopover,
 8753                snapshot,
 8754            } => self.render_edit_prediction_diff_popover(
 8755                text_bounds,
 8756                content_origin,
 8757                right_margin,
 8758                editor_snapshot,
 8759                visible_row_range,
 8760                line_layouts,
 8761                line_height,
 8762                scroll_position,
 8763                scroll_pixel_position,
 8764                newest_selection_head,
 8765                editor_width,
 8766                style,
 8767                edits,
 8768                edit_preview,
 8769                snapshot,
 8770                window,
 8771                cx,
 8772            ),
 8773            EditPrediction::MoveOutside { snapshot, .. } => {
 8774                let file_name = snapshot
 8775                    .file()
 8776                    .map(|file| file.file_name(cx))
 8777                    .unwrap_or("untitled");
 8778                let mut element = self
 8779                    .render_edit_prediction_line_popover(
 8780                        format!("Jump to {file_name}"),
 8781                        Some(IconName::ZedPredict),
 8782                        window,
 8783                        cx,
 8784                    )
 8785                    .into_any();
 8786
 8787                let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8788                let origin_x = text_bounds.size.width / 2. - size.width / 2.;
 8789                let origin_y = text_bounds.size.height - size.height - px(30.);
 8790                let origin = text_bounds.origin + gpui::Point::new(origin_x, origin_y);
 8791                element.prepaint_at(origin, window, cx);
 8792
 8793                Some((element, origin))
 8794            }
 8795        }
 8796    }
 8797
 8798    fn render_edit_prediction_modifier_jump_popover(
 8799        &mut self,
 8800        text_bounds: &Bounds<Pixels>,
 8801        content_origin: gpui::Point<Pixels>,
 8802        visible_row_range: Range<DisplayRow>,
 8803        line_layouts: &[LineWithInvisibles],
 8804        line_height: Pixels,
 8805        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8806        newest_selection_head: Option<DisplayPoint>,
 8807        target_display_point: DisplayPoint,
 8808        window: &mut Window,
 8809        cx: &mut App,
 8810    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8811        let scrolled_content_origin =
 8812            content_origin - gpui::Point::new(scroll_pixel_position.x.into(), Pixels::ZERO);
 8813
 8814        const SCROLL_PADDING_Y: Pixels = px(12.);
 8815
 8816        if target_display_point.row() < visible_row_range.start {
 8817            return self.render_edit_prediction_scroll_popover(
 8818                |_| SCROLL_PADDING_Y,
 8819                IconName::ArrowUp,
 8820                visible_row_range,
 8821                line_layouts,
 8822                newest_selection_head,
 8823                scrolled_content_origin,
 8824                window,
 8825                cx,
 8826            );
 8827        } else if target_display_point.row() >= visible_row_range.end {
 8828            return self.render_edit_prediction_scroll_popover(
 8829                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 8830                IconName::ArrowDown,
 8831                visible_row_range,
 8832                line_layouts,
 8833                newest_selection_head,
 8834                scrolled_content_origin,
 8835                window,
 8836                cx,
 8837            );
 8838        }
 8839
 8840        const POLE_WIDTH: Pixels = px(2.);
 8841
 8842        let line_layout =
 8843            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 8844        let target_column = target_display_point.column() as usize;
 8845
 8846        let target_x = line_layout.x_for_index(target_column);
 8847        let target_y = (target_display_point.row().as_f64() * f64::from(line_height))
 8848            - scroll_pixel_position.y;
 8849
 8850        let flag_on_right = target_x < text_bounds.size.width / 2.;
 8851
 8852        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 8853        border_color.l += 0.001;
 8854
 8855        let mut element = v_flex()
 8856            .items_end()
 8857            .when(flag_on_right, |el| el.items_start())
 8858            .child(if flag_on_right {
 8859                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 8860                    .rounded_bl(px(0.))
 8861                    .rounded_tl(px(0.))
 8862                    .border_l_2()
 8863                    .border_color(border_color)
 8864            } else {
 8865                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 8866                    .rounded_br(px(0.))
 8867                    .rounded_tr(px(0.))
 8868                    .border_r_2()
 8869                    .border_color(border_color)
 8870            })
 8871            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 8872            .into_any();
 8873
 8874        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8875
 8876        let mut origin = scrolled_content_origin + point(target_x, target_y.into())
 8877            - point(
 8878                if flag_on_right {
 8879                    POLE_WIDTH
 8880                } else {
 8881                    size.width - POLE_WIDTH
 8882                },
 8883                size.height - line_height,
 8884            );
 8885
 8886        origin.x = origin.x.max(content_origin.x);
 8887
 8888        element.prepaint_at(origin, window, cx);
 8889
 8890        Some((element, origin))
 8891    }
 8892
 8893    fn render_edit_prediction_scroll_popover(
 8894        &mut self,
 8895        to_y: impl Fn(Size<Pixels>) -> Pixels,
 8896        scroll_icon: IconName,
 8897        visible_row_range: Range<DisplayRow>,
 8898        line_layouts: &[LineWithInvisibles],
 8899        newest_selection_head: Option<DisplayPoint>,
 8900        scrolled_content_origin: gpui::Point<Pixels>,
 8901        window: &mut Window,
 8902        cx: &mut App,
 8903    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8904        let mut element = self
 8905            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)
 8906            .into_any();
 8907
 8908        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8909
 8910        let cursor = newest_selection_head?;
 8911        let cursor_row_layout =
 8912            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 8913        let cursor_column = cursor.column() as usize;
 8914
 8915        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 8916
 8917        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 8918
 8919        element.prepaint_at(origin, window, cx);
 8920        Some((element, origin))
 8921    }
 8922
 8923    fn render_edit_prediction_eager_jump_popover(
 8924        &mut self,
 8925        text_bounds: &Bounds<Pixels>,
 8926        content_origin: gpui::Point<Pixels>,
 8927        editor_snapshot: &EditorSnapshot,
 8928        visible_row_range: Range<DisplayRow>,
 8929        scroll_top: ScrollOffset,
 8930        scroll_bottom: ScrollOffset,
 8931        line_height: Pixels,
 8932        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8933        target_display_point: DisplayPoint,
 8934        editor_width: Pixels,
 8935        window: &mut Window,
 8936        cx: &mut App,
 8937    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8938        if target_display_point.row().as_f64() < scroll_top {
 8939            let mut element = self
 8940                .render_edit_prediction_line_popover(
 8941                    "Jump to Edit",
 8942                    Some(IconName::ArrowUp),
 8943                    window,
 8944                    cx,
 8945                )
 8946                .into_any();
 8947
 8948            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8949            let offset = point(
 8950                (text_bounds.size.width - size.width) / 2.,
 8951                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8952            );
 8953
 8954            let origin = text_bounds.origin + offset;
 8955            element.prepaint_at(origin, window, cx);
 8956            Some((element, origin))
 8957        } else if (target_display_point.row().as_f64() + 1.) > scroll_bottom {
 8958            let mut element = self
 8959                .render_edit_prediction_line_popover(
 8960                    "Jump to Edit",
 8961                    Some(IconName::ArrowDown),
 8962                    window,
 8963                    cx,
 8964                )
 8965                .into_any();
 8966
 8967            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8968            let offset = point(
 8969                (text_bounds.size.width - size.width) / 2.,
 8970                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8971            );
 8972
 8973            let origin = text_bounds.origin + offset;
 8974            element.prepaint_at(origin, window, cx);
 8975            Some((element, origin))
 8976        } else {
 8977            self.render_edit_prediction_end_of_line_popover(
 8978                "Jump to Edit",
 8979                editor_snapshot,
 8980                visible_row_range,
 8981                target_display_point,
 8982                line_height,
 8983                scroll_pixel_position,
 8984                content_origin,
 8985                editor_width,
 8986                window,
 8987                cx,
 8988            )
 8989        }
 8990    }
 8991
 8992    fn render_edit_prediction_end_of_line_popover(
 8993        self: &mut Editor,
 8994        label: &'static str,
 8995        editor_snapshot: &EditorSnapshot,
 8996        visible_row_range: Range<DisplayRow>,
 8997        target_display_point: DisplayPoint,
 8998        line_height: Pixels,
 8999        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9000        content_origin: gpui::Point<Pixels>,
 9001        editor_width: Pixels,
 9002        window: &mut Window,
 9003        cx: &mut App,
 9004    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9005        let target_line_end = DisplayPoint::new(
 9006            target_display_point.row(),
 9007            editor_snapshot.line_len(target_display_point.row()),
 9008        );
 9009
 9010        let mut element = self
 9011            .render_edit_prediction_line_popover(label, None, window, cx)
 9012            .into_any();
 9013
 9014        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9015
 9016        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 9017
 9018        let start_point = content_origin - point(scroll_pixel_position.x.into(), Pixels::ZERO);
 9019        let mut origin = start_point
 9020            + line_origin
 9021            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 9022        origin.x = origin.x.max(content_origin.x);
 9023
 9024        let max_x = content_origin.x + editor_width - size.width;
 9025
 9026        if origin.x > max_x {
 9027            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 9028
 9029            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 9030                origin.y += offset;
 9031                IconName::ArrowUp
 9032            } else {
 9033                origin.y -= offset;
 9034                IconName::ArrowDown
 9035            };
 9036
 9037            element = self
 9038                .render_edit_prediction_line_popover(label, Some(icon), window, cx)
 9039                .into_any();
 9040
 9041            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9042
 9043            origin.x = content_origin.x + editor_width - size.width - px(2.);
 9044        }
 9045
 9046        element.prepaint_at(origin, window, cx);
 9047        Some((element, origin))
 9048    }
 9049
 9050    fn render_edit_prediction_diff_popover(
 9051        self: &Editor,
 9052        text_bounds: &Bounds<Pixels>,
 9053        content_origin: gpui::Point<Pixels>,
 9054        right_margin: Pixels,
 9055        editor_snapshot: &EditorSnapshot,
 9056        visible_row_range: Range<DisplayRow>,
 9057        line_layouts: &[LineWithInvisibles],
 9058        line_height: Pixels,
 9059        scroll_position: gpui::Point<ScrollOffset>,
 9060        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9061        newest_selection_head: Option<DisplayPoint>,
 9062        editor_width: Pixels,
 9063        style: &EditorStyle,
 9064        edits: &Vec<(Range<Anchor>, Arc<str>)>,
 9065        edit_preview: &Option<language::EditPreview>,
 9066        snapshot: &language::BufferSnapshot,
 9067        window: &mut Window,
 9068        cx: &mut App,
 9069    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9070        let edit_start = edits
 9071            .first()
 9072            .unwrap()
 9073            .0
 9074            .start
 9075            .to_display_point(editor_snapshot);
 9076        let edit_end = edits
 9077            .last()
 9078            .unwrap()
 9079            .0
 9080            .end
 9081            .to_display_point(editor_snapshot);
 9082
 9083        let is_visible = visible_row_range.contains(&edit_start.row())
 9084            || visible_row_range.contains(&edit_end.row());
 9085        if !is_visible {
 9086            return None;
 9087        }
 9088
 9089        let highlighted_edits = if let Some(edit_preview) = edit_preview.as_ref() {
 9090            crate::edit_prediction_edit_text(snapshot, edits, edit_preview, false, cx)
 9091        } else {
 9092            // Fallback for providers without edit_preview
 9093            crate::edit_prediction_fallback_text(edits, cx)
 9094        };
 9095
 9096        let styled_text = highlighted_edits.to_styled_text(&style.text);
 9097        let line_count = highlighted_edits.text.lines().count();
 9098
 9099        const BORDER_WIDTH: Pixels = px(1.);
 9100
 9101        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9102        let has_keybind = keybind.is_some();
 9103
 9104        let mut element = h_flex()
 9105            .items_start()
 9106            .child(
 9107                h_flex()
 9108                    .bg(cx.theme().colors().editor_background)
 9109                    .border(BORDER_WIDTH)
 9110                    .shadow_xs()
 9111                    .border_color(cx.theme().colors().border)
 9112                    .rounded_l_lg()
 9113                    .when(line_count > 1, |el| el.rounded_br_lg())
 9114                    .pr_1()
 9115                    .child(styled_text),
 9116            )
 9117            .child(
 9118                h_flex()
 9119                    .h(line_height + BORDER_WIDTH * 2.)
 9120                    .px_1p5()
 9121                    .gap_1()
 9122                    // Workaround: For some reason, there's a gap if we don't do this
 9123                    .ml(-BORDER_WIDTH)
 9124                    .shadow(vec![gpui::BoxShadow {
 9125                        color: gpui::black().opacity(0.05),
 9126                        offset: point(px(1.), px(1.)),
 9127                        blur_radius: px(2.),
 9128                        spread_radius: px(0.),
 9129                    }])
 9130                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 9131                    .border(BORDER_WIDTH)
 9132                    .border_color(cx.theme().colors().border)
 9133                    .rounded_r_lg()
 9134                    .id("edit_prediction_diff_popover_keybind")
 9135                    .when(!has_keybind, |el| {
 9136                        let status_colors = cx.theme().status();
 9137
 9138                        el.bg(status_colors.error_background)
 9139                            .border_color(status_colors.error.opacity(0.6))
 9140                            .child(Icon::new(IconName::Info).color(Color::Error))
 9141                            .cursor_default()
 9142                            .hoverable_tooltip(move |_window, cx| {
 9143                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9144                            })
 9145                    })
 9146                    .children(keybind),
 9147            )
 9148            .into_any();
 9149
 9150        let longest_row =
 9151            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 9152        let longest_line_width = if visible_row_range.contains(&longest_row) {
 9153            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 9154        } else {
 9155            layout_line(
 9156                longest_row,
 9157                editor_snapshot,
 9158                style,
 9159                editor_width,
 9160                |_| false,
 9161                window,
 9162                cx,
 9163            )
 9164            .width
 9165        };
 9166
 9167        let viewport_bounds =
 9168            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 9169                right: -right_margin,
 9170                ..Default::default()
 9171            });
 9172
 9173        let x_after_longest = Pixels::from(
 9174            ScrollPixelOffset::from(
 9175                text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X,
 9176            ) - scroll_pixel_position.x,
 9177        );
 9178
 9179        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9180
 9181        // Fully visible if it can be displayed within the window (allow overlapping other
 9182        // panes). However, this is only allowed if the popover starts within text_bounds.
 9183        let can_position_to_the_right = x_after_longest < text_bounds.right()
 9184            && x_after_longest + element_bounds.width < viewport_bounds.right();
 9185
 9186        let mut origin = if can_position_to_the_right {
 9187            point(
 9188                x_after_longest,
 9189                text_bounds.origin.y
 9190                    + Pixels::from(
 9191                        edit_start.row().as_f64() * ScrollPixelOffset::from(line_height)
 9192                            - scroll_pixel_position.y,
 9193                    ),
 9194            )
 9195        } else {
 9196            let cursor_row = newest_selection_head.map(|head| head.row());
 9197            let above_edit = edit_start
 9198                .row()
 9199                .0
 9200                .checked_sub(line_count as u32)
 9201                .map(DisplayRow);
 9202            let below_edit = Some(edit_end.row() + 1);
 9203            let above_cursor =
 9204                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 9205            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 9206
 9207            // Place the edit popover adjacent to the edit if there is a location
 9208            // available that is onscreen and does not obscure the cursor. Otherwise,
 9209            // place it adjacent to the cursor.
 9210            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 9211                .into_iter()
 9212                .flatten()
 9213                .find(|&start_row| {
 9214                    let end_row = start_row + line_count as u32;
 9215                    visible_row_range.contains(&start_row)
 9216                        && visible_row_range.contains(&end_row)
 9217                        && cursor_row
 9218                            .is_none_or(|cursor_row| !((start_row..end_row).contains(&cursor_row)))
 9219                })?;
 9220
 9221            content_origin
 9222                + point(
 9223                    Pixels::from(-scroll_pixel_position.x),
 9224                    Pixels::from(
 9225                        (row_target.as_f64() - scroll_position.y) * f64::from(line_height),
 9226                    ),
 9227                )
 9228        };
 9229
 9230        origin.x -= BORDER_WIDTH;
 9231
 9232        window.defer_draw(element, origin, 1);
 9233
 9234        // Do not return an element, since it will already be drawn due to defer_draw.
 9235        None
 9236    }
 9237
 9238    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 9239        px(30.)
 9240    }
 9241
 9242    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 9243        if self.read_only(cx) {
 9244            cx.theme().players().read_only()
 9245        } else {
 9246            self.style.as_ref().unwrap().local_player
 9247        }
 9248    }
 9249
 9250    fn render_edit_prediction_accept_keybind(
 9251        &self,
 9252        window: &mut Window,
 9253        cx: &mut App,
 9254    ) -> Option<AnyElement> {
 9255        let accept_binding = self.accept_edit_prediction_keybind(false, window, cx);
 9256        let accept_keystroke = accept_binding.keystroke()?;
 9257
 9258        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9259
 9260        let modifiers_color = if *accept_keystroke.modifiers() == window.modifiers() {
 9261            Color::Accent
 9262        } else {
 9263            Color::Muted
 9264        };
 9265
 9266        h_flex()
 9267            .px_0p5()
 9268            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 9269            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9270            .text_size(TextSize::XSmall.rems(cx))
 9271            .child(h_flex().children(ui::render_modifiers(
 9272                accept_keystroke.modifiers(),
 9273                PlatformStyle::platform(),
 9274                Some(modifiers_color),
 9275                Some(IconSize::XSmall.rems().into()),
 9276                true,
 9277            )))
 9278            .when(is_platform_style_mac, |parent| {
 9279                parent.child(accept_keystroke.key().to_string())
 9280            })
 9281            .when(!is_platform_style_mac, |parent| {
 9282                parent.child(
 9283                    Key::new(
 9284                        util::capitalize(accept_keystroke.key()),
 9285                        Some(Color::Default),
 9286                    )
 9287                    .size(Some(IconSize::XSmall.rems().into())),
 9288                )
 9289            })
 9290            .into_any()
 9291            .into()
 9292    }
 9293
 9294    fn render_edit_prediction_line_popover(
 9295        &self,
 9296        label: impl Into<SharedString>,
 9297        icon: Option<IconName>,
 9298        window: &mut Window,
 9299        cx: &mut App,
 9300    ) -> Stateful<Div> {
 9301        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 9302
 9303        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9304        let has_keybind = keybind.is_some();
 9305
 9306        h_flex()
 9307            .id("ep-line-popover")
 9308            .py_0p5()
 9309            .pl_1()
 9310            .pr(padding_right)
 9311            .gap_1()
 9312            .rounded_md()
 9313            .border_1()
 9314            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9315            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9316            .shadow_xs()
 9317            .when(!has_keybind, |el| {
 9318                let status_colors = cx.theme().status();
 9319
 9320                el.bg(status_colors.error_background)
 9321                    .border_color(status_colors.error.opacity(0.6))
 9322                    .pl_2()
 9323                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9324                    .cursor_default()
 9325                    .hoverable_tooltip(move |_window, cx| {
 9326                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9327                    })
 9328            })
 9329            .children(keybind)
 9330            .child(
 9331                Label::new(label)
 9332                    .size(LabelSize::Small)
 9333                    .when(!has_keybind, |el| {
 9334                        el.color(cx.theme().status().error.into()).strikethrough()
 9335                    }),
 9336            )
 9337            .when(!has_keybind, |el| {
 9338                el.child(
 9339                    h_flex().ml_1().child(
 9340                        Icon::new(IconName::Info)
 9341                            .size(IconSize::Small)
 9342                            .color(cx.theme().status().error.into()),
 9343                    ),
 9344                )
 9345            })
 9346            .when_some(icon, |element, icon| {
 9347                element.child(
 9348                    div()
 9349                        .mt(px(1.5))
 9350                        .child(Icon::new(icon).size(IconSize::Small)),
 9351                )
 9352            })
 9353    }
 9354
 9355    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 9356        let accent_color = cx.theme().colors().text_accent;
 9357        let editor_bg_color = cx.theme().colors().editor_background;
 9358        editor_bg_color.blend(accent_color.opacity(0.1))
 9359    }
 9360
 9361    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 9362        let accent_color = cx.theme().colors().text_accent;
 9363        let editor_bg_color = cx.theme().colors().editor_background;
 9364        editor_bg_color.blend(accent_color.opacity(0.6))
 9365    }
 9366    fn get_prediction_provider_icon_name(
 9367        provider: &Option<RegisteredEditPredictionProvider>,
 9368    ) -> IconName {
 9369        match provider {
 9370            Some(provider) => match provider.provider.name() {
 9371                "copilot" => IconName::Copilot,
 9372                "supermaven" => IconName::Supermaven,
 9373                _ => IconName::ZedPredict,
 9374            },
 9375            None => IconName::ZedPredict,
 9376        }
 9377    }
 9378
 9379    fn render_edit_prediction_cursor_popover(
 9380        &self,
 9381        min_width: Pixels,
 9382        max_width: Pixels,
 9383        cursor_point: Point,
 9384        style: &EditorStyle,
 9385        accept_keystroke: Option<&gpui::KeybindingKeystroke>,
 9386        _window: &Window,
 9387        cx: &mut Context<Editor>,
 9388    ) -> Option<AnyElement> {
 9389        let provider = self.edit_prediction_provider.as_ref()?;
 9390        let provider_icon = Self::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9391
 9392        let is_refreshing = provider.provider.is_refreshing(cx);
 9393
 9394        fn pending_completion_container(icon: IconName) -> Div {
 9395            h_flex().h_full().flex_1().gap_2().child(Icon::new(icon))
 9396        }
 9397
 9398        let completion = match &self.active_edit_prediction {
 9399            Some(prediction) => {
 9400                if !self.has_visible_completions_menu() {
 9401                    const RADIUS: Pixels = px(6.);
 9402                    const BORDER_WIDTH: Pixels = px(1.);
 9403
 9404                    return Some(
 9405                        h_flex()
 9406                            .elevation_2(cx)
 9407                            .border(BORDER_WIDTH)
 9408                            .border_color(cx.theme().colors().border)
 9409                            .when(accept_keystroke.is_none(), |el| {
 9410                                el.border_color(cx.theme().status().error)
 9411                            })
 9412                            .rounded(RADIUS)
 9413                            .rounded_tl(px(0.))
 9414                            .overflow_hidden()
 9415                            .child(div().px_1p5().child(match &prediction.completion {
 9416                                EditPrediction::MoveWithin { target, snapshot } => {
 9417                                    use text::ToPoint as _;
 9418                                    if target.text_anchor.to_point(snapshot).row > cursor_point.row
 9419                                    {
 9420                                        Icon::new(IconName::ZedPredictDown)
 9421                                    } else {
 9422                                        Icon::new(IconName::ZedPredictUp)
 9423                                    }
 9424                                }
 9425                                EditPrediction::MoveOutside { .. } => {
 9426                                    // TODO [zeta2] custom icon for external jump?
 9427                                    Icon::new(provider_icon)
 9428                                }
 9429                                EditPrediction::Edit { .. } => Icon::new(provider_icon),
 9430                            }))
 9431                            .child(
 9432                                h_flex()
 9433                                    .gap_1()
 9434                                    .py_1()
 9435                                    .px_2()
 9436                                    .rounded_r(RADIUS - BORDER_WIDTH)
 9437                                    .border_l_1()
 9438                                    .border_color(cx.theme().colors().border)
 9439                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9440                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 9441                                        el.child(
 9442                                            Label::new("Hold")
 9443                                                .size(LabelSize::Small)
 9444                                                .when(accept_keystroke.is_none(), |el| {
 9445                                                    el.strikethrough()
 9446                                                })
 9447                                                .line_height_style(LineHeightStyle::UiLabel),
 9448                                        )
 9449                                    })
 9450                                    .id("edit_prediction_cursor_popover_keybind")
 9451                                    .when(accept_keystroke.is_none(), |el| {
 9452                                        let status_colors = cx.theme().status();
 9453
 9454                                        el.bg(status_colors.error_background)
 9455                                            .border_color(status_colors.error.opacity(0.6))
 9456                                            .child(Icon::new(IconName::Info).color(Color::Error))
 9457                                            .cursor_default()
 9458                                            .hoverable_tooltip(move |_window, cx| {
 9459                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 9460                                                    .into()
 9461                                            })
 9462                                    })
 9463                                    .when_some(
 9464                                        accept_keystroke.as_ref(),
 9465                                        |el, accept_keystroke| {
 9466                                            el.child(h_flex().children(ui::render_modifiers(
 9467                                                accept_keystroke.modifiers(),
 9468                                                PlatformStyle::platform(),
 9469                                                Some(Color::Default),
 9470                                                Some(IconSize::XSmall.rems().into()),
 9471                                                false,
 9472                                            )))
 9473                                        },
 9474                                    ),
 9475                            )
 9476                            .into_any(),
 9477                    );
 9478                }
 9479
 9480                self.render_edit_prediction_cursor_popover_preview(
 9481                    prediction,
 9482                    cursor_point,
 9483                    style,
 9484                    cx,
 9485                )?
 9486            }
 9487
 9488            None if is_refreshing => match &self.stale_edit_prediction_in_menu {
 9489                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 9490                    stale_completion,
 9491                    cursor_point,
 9492                    style,
 9493                    cx,
 9494                )?,
 9495
 9496                None => pending_completion_container(provider_icon)
 9497                    .child(Label::new("...").size(LabelSize::Small)),
 9498            },
 9499
 9500            None => pending_completion_container(provider_icon)
 9501                .child(Label::new("...").size(LabelSize::Small)),
 9502        };
 9503
 9504        let completion = if is_refreshing || self.active_edit_prediction.is_none() {
 9505            completion
 9506                .with_animation(
 9507                    "loading-completion",
 9508                    Animation::new(Duration::from_secs(2))
 9509                        .repeat()
 9510                        .with_easing(pulsating_between(0.4, 0.8)),
 9511                    |label, delta| label.opacity(delta),
 9512                )
 9513                .into_any_element()
 9514        } else {
 9515            completion.into_any_element()
 9516        };
 9517
 9518        let has_completion = self.active_edit_prediction.is_some();
 9519
 9520        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9521        Some(
 9522            h_flex()
 9523                .min_w(min_width)
 9524                .max_w(max_width)
 9525                .flex_1()
 9526                .elevation_2(cx)
 9527                .border_color(cx.theme().colors().border)
 9528                .child(
 9529                    div()
 9530                        .flex_1()
 9531                        .py_1()
 9532                        .px_2()
 9533                        .overflow_hidden()
 9534                        .child(completion),
 9535                )
 9536                .when_some(accept_keystroke, |el, accept_keystroke| {
 9537                    if !accept_keystroke.modifiers().modified() {
 9538                        return el;
 9539                    }
 9540
 9541                    el.child(
 9542                        h_flex()
 9543                            .h_full()
 9544                            .border_l_1()
 9545                            .rounded_r_lg()
 9546                            .border_color(cx.theme().colors().border)
 9547                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9548                            .gap_1()
 9549                            .py_1()
 9550                            .px_2()
 9551                            .child(
 9552                                h_flex()
 9553                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9554                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 9555                                    .child(h_flex().children(ui::render_modifiers(
 9556                                        accept_keystroke.modifiers(),
 9557                                        PlatformStyle::platform(),
 9558                                        Some(if !has_completion {
 9559                                            Color::Muted
 9560                                        } else {
 9561                                            Color::Default
 9562                                        }),
 9563                                        None,
 9564                                        false,
 9565                                    ))),
 9566                            )
 9567                            .child(Label::new("Preview").into_any_element())
 9568                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 9569                    )
 9570                })
 9571                .into_any(),
 9572        )
 9573    }
 9574
 9575    fn render_edit_prediction_cursor_popover_preview(
 9576        &self,
 9577        completion: &EditPredictionState,
 9578        cursor_point: Point,
 9579        style: &EditorStyle,
 9580        cx: &mut Context<Editor>,
 9581    ) -> Option<Div> {
 9582        use text::ToPoint as _;
 9583
 9584        fn render_relative_row_jump(
 9585            prefix: impl Into<String>,
 9586            current_row: u32,
 9587            target_row: u32,
 9588        ) -> Div {
 9589            let (row_diff, arrow) = if target_row < current_row {
 9590                (current_row - target_row, IconName::ArrowUp)
 9591            } else {
 9592                (target_row - current_row, IconName::ArrowDown)
 9593            };
 9594
 9595            h_flex()
 9596                .child(
 9597                    Label::new(format!("{}{}", prefix.into(), row_diff))
 9598                        .color(Color::Muted)
 9599                        .size(LabelSize::Small),
 9600                )
 9601                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 9602        }
 9603
 9604        let supports_jump = self
 9605            .edit_prediction_provider
 9606            .as_ref()
 9607            .map(|provider| provider.provider.supports_jump_to_edit())
 9608            .unwrap_or(true);
 9609
 9610        match &completion.completion {
 9611            EditPrediction::MoveWithin {
 9612                target, snapshot, ..
 9613            } => {
 9614                if !supports_jump {
 9615                    return None;
 9616                }
 9617
 9618                Some(
 9619                    h_flex()
 9620                        .px_2()
 9621                        .gap_2()
 9622                        .flex_1()
 9623                        .child(
 9624                            if target.text_anchor.to_point(snapshot).row > cursor_point.row {
 9625                                Icon::new(IconName::ZedPredictDown)
 9626                            } else {
 9627                                Icon::new(IconName::ZedPredictUp)
 9628                            },
 9629                        )
 9630                        .child(Label::new("Jump to Edit")),
 9631                )
 9632            }
 9633            EditPrediction::MoveOutside { snapshot, .. } => {
 9634                let file_name = snapshot
 9635                    .file()
 9636                    .map(|file| file.file_name(cx))
 9637                    .unwrap_or("untitled");
 9638                Some(
 9639                    h_flex()
 9640                        .px_2()
 9641                        .gap_2()
 9642                        .flex_1()
 9643                        .child(Icon::new(IconName::ZedPredict))
 9644                        .child(Label::new(format!("Jump to {file_name}"))),
 9645                )
 9646            }
 9647            EditPrediction::Edit {
 9648                edits,
 9649                edit_preview,
 9650                snapshot,
 9651                display_mode: _,
 9652            } => {
 9653                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(snapshot).row;
 9654
 9655                let (highlighted_edits, has_more_lines) =
 9656                    if let Some(edit_preview) = edit_preview.as_ref() {
 9657                        crate::edit_prediction_edit_text(snapshot, edits, edit_preview, true, cx)
 9658                            .first_line_preview()
 9659                    } else {
 9660                        crate::edit_prediction_fallback_text(edits, cx).first_line_preview()
 9661                    };
 9662
 9663                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 9664                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 9665
 9666                let preview = h_flex()
 9667                    .gap_1()
 9668                    .min_w_16()
 9669                    .child(styled_text)
 9670                    .when(has_more_lines, |parent| parent.child(""));
 9671
 9672                let left = if supports_jump && first_edit_row != cursor_point.row {
 9673                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 9674                        .into_any_element()
 9675                } else {
 9676                    let icon_name =
 9677                        Editor::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9678                    Icon::new(icon_name).into_any_element()
 9679                };
 9680
 9681                Some(
 9682                    h_flex()
 9683                        .h_full()
 9684                        .flex_1()
 9685                        .gap_2()
 9686                        .pr_1()
 9687                        .overflow_x_hidden()
 9688                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9689                        .child(left)
 9690                        .child(preview),
 9691                )
 9692            }
 9693        }
 9694    }
 9695
 9696    pub fn render_context_menu(
 9697        &self,
 9698        style: &EditorStyle,
 9699        max_height_in_lines: u32,
 9700        window: &mut Window,
 9701        cx: &mut Context<Editor>,
 9702    ) -> Option<AnyElement> {
 9703        let menu = self.context_menu.borrow();
 9704        let menu = menu.as_ref()?;
 9705        if !menu.visible() {
 9706            return None;
 9707        };
 9708        Some(menu.render(style, max_height_in_lines, window, cx))
 9709    }
 9710
 9711    fn render_context_menu_aside(
 9712        &mut self,
 9713        max_size: Size<Pixels>,
 9714        window: &mut Window,
 9715        cx: &mut Context<Editor>,
 9716    ) -> Option<AnyElement> {
 9717        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 9718            if menu.visible() {
 9719                menu.render_aside(max_size, window, cx)
 9720            } else {
 9721                None
 9722            }
 9723        })
 9724    }
 9725
 9726    fn hide_context_menu(
 9727        &mut self,
 9728        window: &mut Window,
 9729        cx: &mut Context<Self>,
 9730    ) -> Option<CodeContextMenu> {
 9731        cx.notify();
 9732        self.completion_tasks.clear();
 9733        let context_menu = self.context_menu.borrow_mut().take();
 9734        self.stale_edit_prediction_in_menu.take();
 9735        self.update_visible_edit_prediction(window, cx);
 9736        if let Some(CodeContextMenu::Completions(_)) = &context_menu
 9737            && let Some(completion_provider) = &self.completion_provider
 9738        {
 9739            completion_provider.selection_changed(None, window, cx);
 9740        }
 9741        context_menu
 9742    }
 9743
 9744    fn show_snippet_choices(
 9745        &mut self,
 9746        choices: &Vec<String>,
 9747        selection: Range<Anchor>,
 9748        cx: &mut Context<Self>,
 9749    ) {
 9750        let Some((_, buffer, _)) = self
 9751            .buffer()
 9752            .read(cx)
 9753            .excerpt_containing(selection.start, cx)
 9754        else {
 9755            return;
 9756        };
 9757        let Some((_, end_buffer, _)) = self.buffer().read(cx).excerpt_containing(selection.end, cx)
 9758        else {
 9759            return;
 9760        };
 9761        if buffer != end_buffer {
 9762            log::error!("expected anchor range to have matching buffer IDs");
 9763            return;
 9764        }
 9765
 9766        let id = post_inc(&mut self.next_completion_id);
 9767        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 9768        *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 9769            CompletionsMenu::new_snippet_choices(
 9770                id,
 9771                true,
 9772                choices,
 9773                selection,
 9774                buffer,
 9775                snippet_sort_order,
 9776            ),
 9777        ));
 9778    }
 9779
 9780    pub fn insert_snippet(
 9781        &mut self,
 9782        insertion_ranges: &[Range<usize>],
 9783        snippet: Snippet,
 9784        window: &mut Window,
 9785        cx: &mut Context<Self>,
 9786    ) -> Result<()> {
 9787        struct Tabstop<T> {
 9788            is_end_tabstop: bool,
 9789            ranges: Vec<Range<T>>,
 9790            choices: Option<Vec<String>>,
 9791        }
 9792
 9793        let tabstops = self.buffer.update(cx, |buffer, cx| {
 9794            let snippet_text: Arc<str> = snippet.text.clone().into();
 9795            let edits = insertion_ranges
 9796                .iter()
 9797                .cloned()
 9798                .map(|range| (range, snippet_text.clone()));
 9799            let autoindent_mode = AutoindentMode::Block {
 9800                original_indent_columns: Vec::new(),
 9801            };
 9802            buffer.edit(edits, Some(autoindent_mode), cx);
 9803
 9804            let snapshot = &*buffer.read(cx);
 9805            let snippet = &snippet;
 9806            snippet
 9807                .tabstops
 9808                .iter()
 9809                .map(|tabstop| {
 9810                    let is_end_tabstop = tabstop.ranges.first().is_some_and(|tabstop| {
 9811                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 9812                    });
 9813                    let mut tabstop_ranges = tabstop
 9814                        .ranges
 9815                        .iter()
 9816                        .flat_map(|tabstop_range| {
 9817                            let mut delta = 0_isize;
 9818                            insertion_ranges.iter().map(move |insertion_range| {
 9819                                let insertion_start = insertion_range.start as isize + delta;
 9820                                delta +=
 9821                                    snippet.text.len() as isize - insertion_range.len() as isize;
 9822
 9823                                let start = ((insertion_start + tabstop_range.start) as usize)
 9824                                    .min(snapshot.len());
 9825                                let end = ((insertion_start + tabstop_range.end) as usize)
 9826                                    .min(snapshot.len());
 9827                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 9828                            })
 9829                        })
 9830                        .collect::<Vec<_>>();
 9831                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 9832
 9833                    Tabstop {
 9834                        is_end_tabstop,
 9835                        ranges: tabstop_ranges,
 9836                        choices: tabstop.choices.clone(),
 9837                    }
 9838                })
 9839                .collect::<Vec<_>>()
 9840        });
 9841        if let Some(tabstop) = tabstops.first() {
 9842            self.change_selections(Default::default(), window, cx, |s| {
 9843                // Reverse order so that the first range is the newest created selection.
 9844                // Completions will use it and autoscroll will prioritize it.
 9845                s.select_ranges(tabstop.ranges.iter().rev().cloned());
 9846            });
 9847
 9848            if let Some(choices) = &tabstop.choices
 9849                && let Some(selection) = tabstop.ranges.first()
 9850            {
 9851                self.show_snippet_choices(choices, selection.clone(), cx)
 9852            }
 9853
 9854            // If we're already at the last tabstop and it's at the end of the snippet,
 9855            // we're done, we don't need to keep the state around.
 9856            if !tabstop.is_end_tabstop {
 9857                let choices = tabstops
 9858                    .iter()
 9859                    .map(|tabstop| tabstop.choices.clone())
 9860                    .collect();
 9861
 9862                let ranges = tabstops
 9863                    .into_iter()
 9864                    .map(|tabstop| tabstop.ranges)
 9865                    .collect::<Vec<_>>();
 9866
 9867                self.snippet_stack.push(SnippetState {
 9868                    active_index: 0,
 9869                    ranges,
 9870                    choices,
 9871                });
 9872            }
 9873
 9874            // Check whether the just-entered snippet ends with an auto-closable bracket.
 9875            if self.autoclose_regions.is_empty() {
 9876                let snapshot = self.buffer.read(cx).snapshot(cx);
 9877                for selection in &mut self.selections.all::<Point>(&self.display_snapshot(cx)) {
 9878                    let selection_head = selection.head();
 9879                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 9880                        continue;
 9881                    };
 9882
 9883                    let mut bracket_pair = None;
 9884                    let max_lookup_length = scope
 9885                        .brackets()
 9886                        .map(|(pair, _)| {
 9887                            pair.start
 9888                                .as_str()
 9889                                .chars()
 9890                                .count()
 9891                                .max(pair.end.as_str().chars().count())
 9892                        })
 9893                        .max();
 9894                    if let Some(max_lookup_length) = max_lookup_length {
 9895                        let next_text = snapshot
 9896                            .chars_at(selection_head)
 9897                            .take(max_lookup_length)
 9898                            .collect::<String>();
 9899                        let prev_text = snapshot
 9900                            .reversed_chars_at(selection_head)
 9901                            .take(max_lookup_length)
 9902                            .collect::<String>();
 9903
 9904                        for (pair, enabled) in scope.brackets() {
 9905                            if enabled
 9906                                && pair.close
 9907                                && prev_text.starts_with(pair.start.as_str())
 9908                                && next_text.starts_with(pair.end.as_str())
 9909                            {
 9910                                bracket_pair = Some(pair.clone());
 9911                                break;
 9912                            }
 9913                        }
 9914                    }
 9915
 9916                    if let Some(pair) = bracket_pair {
 9917                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 9918                        let autoclose_enabled =
 9919                            self.use_autoclose && snapshot_settings.use_autoclose;
 9920                        if autoclose_enabled {
 9921                            let start = snapshot.anchor_after(selection_head);
 9922                            let end = snapshot.anchor_after(selection_head);
 9923                            self.autoclose_regions.push(AutocloseRegion {
 9924                                selection_id: selection.id,
 9925                                range: start..end,
 9926                                pair,
 9927                            });
 9928                        }
 9929                    }
 9930                }
 9931            }
 9932        }
 9933        Ok(())
 9934    }
 9935
 9936    pub fn move_to_next_snippet_tabstop(
 9937        &mut self,
 9938        window: &mut Window,
 9939        cx: &mut Context<Self>,
 9940    ) -> bool {
 9941        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 9942    }
 9943
 9944    pub fn move_to_prev_snippet_tabstop(
 9945        &mut self,
 9946        window: &mut Window,
 9947        cx: &mut Context<Self>,
 9948    ) -> bool {
 9949        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 9950    }
 9951
 9952    pub fn move_to_snippet_tabstop(
 9953        &mut self,
 9954        bias: Bias,
 9955        window: &mut Window,
 9956        cx: &mut Context<Self>,
 9957    ) -> bool {
 9958        if let Some(mut snippet) = self.snippet_stack.pop() {
 9959            match bias {
 9960                Bias::Left => {
 9961                    if snippet.active_index > 0 {
 9962                        snippet.active_index -= 1;
 9963                    } else {
 9964                        self.snippet_stack.push(snippet);
 9965                        return false;
 9966                    }
 9967                }
 9968                Bias::Right => {
 9969                    if snippet.active_index + 1 < snippet.ranges.len() {
 9970                        snippet.active_index += 1;
 9971                    } else {
 9972                        self.snippet_stack.push(snippet);
 9973                        return false;
 9974                    }
 9975                }
 9976            }
 9977            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 9978                self.change_selections(Default::default(), window, cx, |s| {
 9979                    // Reverse order so that the first range is the newest created selection.
 9980                    // Completions will use it and autoscroll will prioritize it.
 9981                    s.select_ranges(current_ranges.iter().rev().cloned())
 9982                });
 9983
 9984                if let Some(choices) = &snippet.choices[snippet.active_index]
 9985                    && let Some(selection) = current_ranges.first()
 9986                {
 9987                    self.show_snippet_choices(choices, selection.clone(), cx);
 9988                }
 9989
 9990                // If snippet state is not at the last tabstop, push it back on the stack
 9991                if snippet.active_index + 1 < snippet.ranges.len() {
 9992                    self.snippet_stack.push(snippet);
 9993                }
 9994                return true;
 9995            }
 9996        }
 9997
 9998        false
 9999    }
10000
10001    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
10002        self.transact(window, cx, |this, window, cx| {
10003            this.select_all(&SelectAll, window, cx);
10004            this.insert("", window, cx);
10005        });
10006    }
10007
10008    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
10009        if self.read_only(cx) {
10010            return;
10011        }
10012        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10013        self.transact(window, cx, |this, window, cx| {
10014            this.select_autoclose_pair(window, cx);
10015
10016            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
10017
10018            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
10019            if !this.linked_edit_ranges.is_empty() {
10020                let selections = this.selections.all::<MultiBufferPoint>(&display_map);
10021                let snapshot = this.buffer.read(cx).snapshot(cx);
10022
10023                for selection in selections.iter() {
10024                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
10025                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
10026                    if selection_start.buffer_id != selection_end.buffer_id {
10027                        continue;
10028                    }
10029                    if let Some(ranges) =
10030                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
10031                    {
10032                        for (buffer, entries) in ranges {
10033                            linked_ranges.entry(buffer).or_default().extend(entries);
10034                        }
10035                    }
10036                }
10037            }
10038
10039            let mut selections = this.selections.all::<MultiBufferPoint>(&display_map);
10040            for selection in &mut selections {
10041                if selection.is_empty() {
10042                    let old_head = selection.head();
10043                    let mut new_head =
10044                        movement::left(&display_map, old_head.to_display_point(&display_map))
10045                            .to_point(&display_map);
10046                    if let Some((buffer, line_buffer_range)) = display_map
10047                        .buffer_snapshot()
10048                        .buffer_line_for_row(MultiBufferRow(old_head.row))
10049                    {
10050                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
10051                        let indent_len = match indent_size.kind {
10052                            IndentKind::Space => {
10053                                buffer.settings_at(line_buffer_range.start, cx).tab_size
10054                            }
10055                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
10056                        };
10057                        if old_head.column <= indent_size.len && old_head.column > 0 {
10058                            let indent_len = indent_len.get();
10059                            new_head = cmp::min(
10060                                new_head,
10061                                MultiBufferPoint::new(
10062                                    old_head.row,
10063                                    ((old_head.column - 1) / indent_len) * indent_len,
10064                                ),
10065                            );
10066                        }
10067                    }
10068
10069                    selection.set_head(new_head, SelectionGoal::None);
10070                }
10071            }
10072
10073            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10074            this.insert("", window, cx);
10075            let empty_str: Arc<str> = Arc::from("");
10076            for (buffer, edits) in linked_ranges {
10077                let snapshot = buffer.read(cx).snapshot();
10078                use text::ToPoint as TP;
10079
10080                let edits = edits
10081                    .into_iter()
10082                    .map(|range| {
10083                        let end_point = TP::to_point(&range.end, &snapshot);
10084                        let mut start_point = TP::to_point(&range.start, &snapshot);
10085
10086                        if end_point == start_point {
10087                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
10088                                .saturating_sub(1);
10089                            start_point =
10090                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
10091                        };
10092
10093                        (start_point..end_point, empty_str.clone())
10094                    })
10095                    .sorted_by_key(|(range, _)| range.start)
10096                    .collect::<Vec<_>>();
10097                buffer.update(cx, |this, cx| {
10098                    this.edit(edits, None, cx);
10099                })
10100            }
10101            this.refresh_edit_prediction(true, false, window, cx);
10102            refresh_linked_ranges(this, window, cx);
10103        });
10104    }
10105
10106    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
10107        if self.read_only(cx) {
10108            return;
10109        }
10110        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10111        self.transact(window, cx, |this, window, cx| {
10112            this.change_selections(Default::default(), window, cx, |s| {
10113                s.move_with(|map, selection| {
10114                    if selection.is_empty() {
10115                        let cursor = movement::right(map, selection.head());
10116                        selection.end = cursor;
10117                        selection.reversed = true;
10118                        selection.goal = SelectionGoal::None;
10119                    }
10120                })
10121            });
10122            this.insert("", window, cx);
10123            this.refresh_edit_prediction(true, false, window, cx);
10124        });
10125    }
10126
10127    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
10128        if self.mode.is_single_line() {
10129            cx.propagate();
10130            return;
10131        }
10132
10133        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10134        if self.move_to_prev_snippet_tabstop(window, cx) {
10135            return;
10136        }
10137        self.outdent(&Outdent, window, cx);
10138    }
10139
10140    pub fn next_snippet_tabstop(
10141        &mut self,
10142        _: &NextSnippetTabstop,
10143        window: &mut Window,
10144        cx: &mut Context<Self>,
10145    ) {
10146        if self.mode.is_single_line() || self.snippet_stack.is_empty() {
10147            cx.propagate();
10148            return;
10149        }
10150
10151        if self.move_to_next_snippet_tabstop(window, cx) {
10152            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10153            return;
10154        }
10155        cx.propagate();
10156    }
10157
10158    pub fn previous_snippet_tabstop(
10159        &mut self,
10160        _: &PreviousSnippetTabstop,
10161        window: &mut Window,
10162        cx: &mut Context<Self>,
10163    ) {
10164        if self.mode.is_single_line() || self.snippet_stack.is_empty() {
10165            cx.propagate();
10166            return;
10167        }
10168
10169        if self.move_to_prev_snippet_tabstop(window, cx) {
10170            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10171            return;
10172        }
10173        cx.propagate();
10174    }
10175
10176    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
10177        if self.mode.is_single_line() {
10178            cx.propagate();
10179            return;
10180        }
10181
10182        if self.move_to_next_snippet_tabstop(window, cx) {
10183            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10184            return;
10185        }
10186        if self.read_only(cx) {
10187            return;
10188        }
10189        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10190        let mut selections = self.selections.all_adjusted(&self.display_snapshot(cx));
10191        let buffer = self.buffer.read(cx);
10192        let snapshot = buffer.snapshot(cx);
10193        let rows_iter = selections.iter().map(|s| s.head().row);
10194        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
10195
10196        let has_some_cursor_in_whitespace = selections
10197            .iter()
10198            .filter(|selection| selection.is_empty())
10199            .any(|selection| {
10200                let cursor = selection.head();
10201                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10202                cursor.column < current_indent.len
10203            });
10204
10205        let mut edits = Vec::new();
10206        let mut prev_edited_row = 0;
10207        let mut row_delta = 0;
10208        for selection in &mut selections {
10209            if selection.start.row != prev_edited_row {
10210                row_delta = 0;
10211            }
10212            prev_edited_row = selection.end.row;
10213
10214            // If the selection is non-empty, then increase the indentation of the selected lines.
10215            if !selection.is_empty() {
10216                row_delta =
10217                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10218                continue;
10219            }
10220
10221            let cursor = selection.head();
10222            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10223            if let Some(suggested_indent) =
10224                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
10225            {
10226                // Don't do anything if already at suggested indent
10227                // and there is any other cursor which is not
10228                if has_some_cursor_in_whitespace
10229                    && cursor.column == current_indent.len
10230                    && current_indent.len == suggested_indent.len
10231                {
10232                    continue;
10233                }
10234
10235                // Adjust line and move cursor to suggested indent
10236                // if cursor is not at suggested indent
10237                if cursor.column < suggested_indent.len
10238                    && cursor.column <= current_indent.len
10239                    && current_indent.len <= suggested_indent.len
10240                {
10241                    selection.start = Point::new(cursor.row, suggested_indent.len);
10242                    selection.end = selection.start;
10243                    if row_delta == 0 {
10244                        edits.extend(Buffer::edit_for_indent_size_adjustment(
10245                            cursor.row,
10246                            current_indent,
10247                            suggested_indent,
10248                        ));
10249                        row_delta = suggested_indent.len - current_indent.len;
10250                    }
10251                    continue;
10252                }
10253
10254                // If current indent is more than suggested indent
10255                // only move cursor to current indent and skip indent
10256                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
10257                    selection.start = Point::new(cursor.row, current_indent.len);
10258                    selection.end = selection.start;
10259                    continue;
10260                }
10261            }
10262
10263            // Otherwise, insert a hard or soft tab.
10264            let settings = buffer.language_settings_at(cursor, cx);
10265            let tab_size = if settings.hard_tabs {
10266                IndentSize::tab()
10267            } else {
10268                let tab_size = settings.tab_size.get();
10269                let indent_remainder = snapshot
10270                    .text_for_range(Point::new(cursor.row, 0)..cursor)
10271                    .flat_map(str::chars)
10272                    .fold(row_delta % tab_size, |counter: u32, c| {
10273                        if c == '\t' {
10274                            0
10275                        } else {
10276                            (counter + 1) % tab_size
10277                        }
10278                    });
10279
10280                let chars_to_next_tab_stop = tab_size - indent_remainder;
10281                IndentSize::spaces(chars_to_next_tab_stop)
10282            };
10283            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
10284            selection.end = selection.start;
10285            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
10286            row_delta += tab_size.len;
10287        }
10288
10289        self.transact(window, cx, |this, window, cx| {
10290            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10291            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10292            this.refresh_edit_prediction(true, false, window, cx);
10293        });
10294    }
10295
10296    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
10297        if self.read_only(cx) {
10298            return;
10299        }
10300        if self.mode.is_single_line() {
10301            cx.propagate();
10302            return;
10303        }
10304
10305        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10306        let mut selections = self.selections.all::<Point>(&self.display_snapshot(cx));
10307        let mut prev_edited_row = 0;
10308        let mut row_delta = 0;
10309        let mut edits = Vec::new();
10310        let buffer = self.buffer.read(cx);
10311        let snapshot = buffer.snapshot(cx);
10312        for selection in &mut selections {
10313            if selection.start.row != prev_edited_row {
10314                row_delta = 0;
10315            }
10316            prev_edited_row = selection.end.row;
10317
10318            row_delta =
10319                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10320        }
10321
10322        self.transact(window, cx, |this, window, cx| {
10323            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10324            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10325        });
10326    }
10327
10328    fn indent_selection(
10329        buffer: &MultiBuffer,
10330        snapshot: &MultiBufferSnapshot,
10331        selection: &mut Selection<Point>,
10332        edits: &mut Vec<(Range<Point>, String)>,
10333        delta_for_start_row: u32,
10334        cx: &App,
10335    ) -> u32 {
10336        let settings = buffer.language_settings_at(selection.start, cx);
10337        let tab_size = settings.tab_size.get();
10338        let indent_kind = if settings.hard_tabs {
10339            IndentKind::Tab
10340        } else {
10341            IndentKind::Space
10342        };
10343        let mut start_row = selection.start.row;
10344        let mut end_row = selection.end.row + 1;
10345
10346        // If a selection ends at the beginning of a line, don't indent
10347        // that last line.
10348        if selection.end.column == 0 && selection.end.row > selection.start.row {
10349            end_row -= 1;
10350        }
10351
10352        // Avoid re-indenting a row that has already been indented by a
10353        // previous selection, but still update this selection's column
10354        // to reflect that indentation.
10355        if delta_for_start_row > 0 {
10356            start_row += 1;
10357            selection.start.column += delta_for_start_row;
10358            if selection.end.row == selection.start.row {
10359                selection.end.column += delta_for_start_row;
10360            }
10361        }
10362
10363        let mut delta_for_end_row = 0;
10364        let has_multiple_rows = start_row + 1 != end_row;
10365        for row in start_row..end_row {
10366            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
10367            let indent_delta = match (current_indent.kind, indent_kind) {
10368                (IndentKind::Space, IndentKind::Space) => {
10369                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
10370                    IndentSize::spaces(columns_to_next_tab_stop)
10371                }
10372                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
10373                (_, IndentKind::Tab) => IndentSize::tab(),
10374            };
10375
10376            let start = if has_multiple_rows || current_indent.len < selection.start.column {
10377                0
10378            } else {
10379                selection.start.column
10380            };
10381            let row_start = Point::new(row, start);
10382            edits.push((
10383                row_start..row_start,
10384                indent_delta.chars().collect::<String>(),
10385            ));
10386
10387            // Update this selection's endpoints to reflect the indentation.
10388            if row == selection.start.row {
10389                selection.start.column += indent_delta.len;
10390            }
10391            if row == selection.end.row {
10392                selection.end.column += indent_delta.len;
10393                delta_for_end_row = indent_delta.len;
10394            }
10395        }
10396
10397        if selection.start.row == selection.end.row {
10398            delta_for_start_row + delta_for_end_row
10399        } else {
10400            delta_for_end_row
10401        }
10402    }
10403
10404    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
10405        if self.read_only(cx) {
10406            return;
10407        }
10408        if self.mode.is_single_line() {
10409            cx.propagate();
10410            return;
10411        }
10412
10413        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10414        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10415        let selections = self.selections.all::<Point>(&display_map);
10416        let mut deletion_ranges = Vec::new();
10417        let mut last_outdent = None;
10418        {
10419            let buffer = self.buffer.read(cx);
10420            let snapshot = buffer.snapshot(cx);
10421            for selection in &selections {
10422                let settings = buffer.language_settings_at(selection.start, cx);
10423                let tab_size = settings.tab_size.get();
10424                let mut rows = selection.spanned_rows(false, &display_map);
10425
10426                // Avoid re-outdenting a row that has already been outdented by a
10427                // previous selection.
10428                if let Some(last_row) = last_outdent
10429                    && last_row == rows.start
10430                {
10431                    rows.start = rows.start.next_row();
10432                }
10433                let has_multiple_rows = rows.len() > 1;
10434                for row in rows.iter_rows() {
10435                    let indent_size = snapshot.indent_size_for_line(row);
10436                    if indent_size.len > 0 {
10437                        let deletion_len = match indent_size.kind {
10438                            IndentKind::Space => {
10439                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
10440                                if columns_to_prev_tab_stop == 0 {
10441                                    tab_size
10442                                } else {
10443                                    columns_to_prev_tab_stop
10444                                }
10445                            }
10446                            IndentKind::Tab => 1,
10447                        };
10448                        let start = if has_multiple_rows
10449                            || deletion_len > selection.start.column
10450                            || indent_size.len < selection.start.column
10451                        {
10452                            0
10453                        } else {
10454                            selection.start.column - deletion_len
10455                        };
10456                        deletion_ranges.push(
10457                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
10458                        );
10459                        last_outdent = Some(row);
10460                    }
10461                }
10462            }
10463        }
10464
10465        self.transact(window, cx, |this, window, cx| {
10466            this.buffer.update(cx, |buffer, cx| {
10467                let empty_str: Arc<str> = Arc::default();
10468                buffer.edit(
10469                    deletion_ranges
10470                        .into_iter()
10471                        .map(|range| (range, empty_str.clone())),
10472                    None,
10473                    cx,
10474                );
10475            });
10476            let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
10477            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10478        });
10479    }
10480
10481    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
10482        if self.read_only(cx) {
10483            return;
10484        }
10485        if self.mode.is_single_line() {
10486            cx.propagate();
10487            return;
10488        }
10489
10490        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10491        let selections = self
10492            .selections
10493            .all::<usize>(&self.display_snapshot(cx))
10494            .into_iter()
10495            .map(|s| s.range());
10496
10497        self.transact(window, cx, |this, window, cx| {
10498            this.buffer.update(cx, |buffer, cx| {
10499                buffer.autoindent_ranges(selections, cx);
10500            });
10501            let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
10502            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10503        });
10504    }
10505
10506    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
10507        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10508        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10509        let selections = self.selections.all::<Point>(&display_map);
10510
10511        let mut new_cursors = Vec::new();
10512        let mut edit_ranges = Vec::new();
10513        let mut selections = selections.iter().peekable();
10514        while let Some(selection) = selections.next() {
10515            let mut rows = selection.spanned_rows(false, &display_map);
10516
10517            // Accumulate contiguous regions of rows that we want to delete.
10518            while let Some(next_selection) = selections.peek() {
10519                let next_rows = next_selection.spanned_rows(false, &display_map);
10520                if next_rows.start <= rows.end {
10521                    rows.end = next_rows.end;
10522                    selections.next().unwrap();
10523                } else {
10524                    break;
10525                }
10526            }
10527
10528            let buffer = display_map.buffer_snapshot();
10529            let mut edit_start = ToOffset::to_offset(&Point::new(rows.start.0, 0), buffer);
10530            let (edit_end, target_row) = if buffer.max_point().row >= rows.end.0 {
10531                // If there's a line after the range, delete the \n from the end of the row range
10532                (
10533                    ToOffset::to_offset(&Point::new(rows.end.0, 0), buffer),
10534                    rows.end,
10535                )
10536            } else {
10537                // If there isn't a line after the range, delete the \n from the line before the
10538                // start of the row range
10539                edit_start = edit_start.saturating_sub(1);
10540                (buffer.len(), rows.start.previous_row())
10541            };
10542
10543            let text_layout_details = self.text_layout_details(window);
10544            let x = display_map.x_for_display_point(
10545                selection.head().to_display_point(&display_map),
10546                &text_layout_details,
10547            );
10548            let row = Point::new(target_row.0, 0)
10549                .to_display_point(&display_map)
10550                .row();
10551            let column = display_map.display_column_for_x(row, x, &text_layout_details);
10552
10553            new_cursors.push((
10554                selection.id,
10555                buffer.anchor_after(DisplayPoint::new(row, column).to_point(&display_map)),
10556                SelectionGoal::None,
10557            ));
10558            edit_ranges.push(edit_start..edit_end);
10559        }
10560
10561        self.transact(window, cx, |this, window, cx| {
10562            let buffer = this.buffer.update(cx, |buffer, cx| {
10563                let empty_str: Arc<str> = Arc::default();
10564                buffer.edit(
10565                    edit_ranges
10566                        .into_iter()
10567                        .map(|range| (range, empty_str.clone())),
10568                    None,
10569                    cx,
10570                );
10571                buffer.snapshot(cx)
10572            });
10573            let new_selections = new_cursors
10574                .into_iter()
10575                .map(|(id, cursor, goal)| {
10576                    let cursor = cursor.to_point(&buffer);
10577                    Selection {
10578                        id,
10579                        start: cursor,
10580                        end: cursor,
10581                        reversed: false,
10582                        goal,
10583                    }
10584                })
10585                .collect();
10586
10587            this.change_selections(Default::default(), window, cx, |s| {
10588                s.select(new_selections);
10589            });
10590        });
10591    }
10592
10593    pub fn join_lines_impl(
10594        &mut self,
10595        insert_whitespace: bool,
10596        window: &mut Window,
10597        cx: &mut Context<Self>,
10598    ) {
10599        if self.read_only(cx) {
10600            return;
10601        }
10602        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
10603        for selection in self.selections.all::<Point>(&self.display_snapshot(cx)) {
10604            let start = MultiBufferRow(selection.start.row);
10605            // Treat single line selections as if they include the next line. Otherwise this action
10606            // would do nothing for single line selections individual cursors.
10607            let end = if selection.start.row == selection.end.row {
10608                MultiBufferRow(selection.start.row + 1)
10609            } else {
10610                MultiBufferRow(selection.end.row)
10611            };
10612
10613            if let Some(last_row_range) = row_ranges.last_mut()
10614                && start <= last_row_range.end
10615            {
10616                last_row_range.end = end;
10617                continue;
10618            }
10619            row_ranges.push(start..end);
10620        }
10621
10622        let snapshot = self.buffer.read(cx).snapshot(cx);
10623        let mut cursor_positions = Vec::new();
10624        for row_range in &row_ranges {
10625            let anchor = snapshot.anchor_before(Point::new(
10626                row_range.end.previous_row().0,
10627                snapshot.line_len(row_range.end.previous_row()),
10628            ));
10629            cursor_positions.push(anchor..anchor);
10630        }
10631
10632        self.transact(window, cx, |this, window, cx| {
10633            for row_range in row_ranges.into_iter().rev() {
10634                for row in row_range.iter_rows().rev() {
10635                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
10636                    let next_line_row = row.next_row();
10637                    let indent = snapshot.indent_size_for_line(next_line_row);
10638                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
10639
10640                    let replace =
10641                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
10642                            " "
10643                        } else {
10644                            ""
10645                        };
10646
10647                    this.buffer.update(cx, |buffer, cx| {
10648                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
10649                    });
10650                }
10651            }
10652
10653            this.change_selections(Default::default(), window, cx, |s| {
10654                s.select_anchor_ranges(cursor_positions)
10655            });
10656        });
10657    }
10658
10659    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
10660        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10661        self.join_lines_impl(true, window, cx);
10662    }
10663
10664    pub fn sort_lines_case_sensitive(
10665        &mut self,
10666        _: &SortLinesCaseSensitive,
10667        window: &mut Window,
10668        cx: &mut Context<Self>,
10669    ) {
10670        self.manipulate_immutable_lines(window, cx, |lines| lines.sort())
10671    }
10672
10673    pub fn sort_lines_by_length(
10674        &mut self,
10675        _: &SortLinesByLength,
10676        window: &mut Window,
10677        cx: &mut Context<Self>,
10678    ) {
10679        self.manipulate_immutable_lines(window, cx, |lines| {
10680            lines.sort_by_key(|&line| line.chars().count())
10681        })
10682    }
10683
10684    pub fn sort_lines_case_insensitive(
10685        &mut self,
10686        _: &SortLinesCaseInsensitive,
10687        window: &mut Window,
10688        cx: &mut Context<Self>,
10689    ) {
10690        self.manipulate_immutable_lines(window, cx, |lines| {
10691            lines.sort_by_key(|line| line.to_lowercase())
10692        })
10693    }
10694
10695    pub fn unique_lines_case_insensitive(
10696        &mut self,
10697        _: &UniqueLinesCaseInsensitive,
10698        window: &mut Window,
10699        cx: &mut Context<Self>,
10700    ) {
10701        self.manipulate_immutable_lines(window, cx, |lines| {
10702            let mut seen = HashSet::default();
10703            lines.retain(|line| seen.insert(line.to_lowercase()));
10704        })
10705    }
10706
10707    pub fn unique_lines_case_sensitive(
10708        &mut self,
10709        _: &UniqueLinesCaseSensitive,
10710        window: &mut Window,
10711        cx: &mut Context<Self>,
10712    ) {
10713        self.manipulate_immutable_lines(window, cx, |lines| {
10714            let mut seen = HashSet::default();
10715            lines.retain(|line| seen.insert(*line));
10716        })
10717    }
10718
10719    fn enable_wrap_selections_in_tag(&self, cx: &App) -> bool {
10720        let snapshot = self.buffer.read(cx).snapshot(cx);
10721        for selection in self.selections.disjoint_anchors_arc().iter() {
10722            if snapshot
10723                .language_at(selection.start)
10724                .and_then(|lang| lang.config().wrap_characters.as_ref())
10725                .is_some()
10726            {
10727                return true;
10728            }
10729        }
10730        false
10731    }
10732
10733    fn wrap_selections_in_tag(
10734        &mut self,
10735        _: &WrapSelectionsInTag,
10736        window: &mut Window,
10737        cx: &mut Context<Self>,
10738    ) {
10739        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10740
10741        let snapshot = self.buffer.read(cx).snapshot(cx);
10742
10743        let mut edits = Vec::new();
10744        let mut boundaries = Vec::new();
10745
10746        for selection in self
10747            .selections
10748            .all_adjusted(&self.display_snapshot(cx))
10749            .iter()
10750        {
10751            let Some(wrap_config) = snapshot
10752                .language_at(selection.start)
10753                .and_then(|lang| lang.config().wrap_characters.clone())
10754            else {
10755                continue;
10756            };
10757
10758            let open_tag = format!("{}{}", wrap_config.start_prefix, wrap_config.start_suffix);
10759            let close_tag = format!("{}{}", wrap_config.end_prefix, wrap_config.end_suffix);
10760
10761            let start_before = snapshot.anchor_before(selection.start);
10762            let end_after = snapshot.anchor_after(selection.end);
10763
10764            edits.push((start_before..start_before, open_tag));
10765            edits.push((end_after..end_after, close_tag));
10766
10767            boundaries.push((
10768                start_before,
10769                end_after,
10770                wrap_config.start_prefix.len(),
10771                wrap_config.end_suffix.len(),
10772            ));
10773        }
10774
10775        if edits.is_empty() {
10776            return;
10777        }
10778
10779        self.transact(window, cx, |this, window, cx| {
10780            let buffer = this.buffer.update(cx, |buffer, cx| {
10781                buffer.edit(edits, None, cx);
10782                buffer.snapshot(cx)
10783            });
10784
10785            let mut new_selections = Vec::with_capacity(boundaries.len() * 2);
10786            for (start_before, end_after, start_prefix_len, end_suffix_len) in
10787                boundaries.into_iter()
10788            {
10789                let open_offset = start_before.to_offset(&buffer) + start_prefix_len;
10790                let close_offset = end_after.to_offset(&buffer).saturating_sub(end_suffix_len);
10791                new_selections.push(open_offset..open_offset);
10792                new_selections.push(close_offset..close_offset);
10793            }
10794
10795            this.change_selections(Default::default(), window, cx, |s| {
10796                s.select_ranges(new_selections);
10797            });
10798
10799            this.request_autoscroll(Autoscroll::fit(), cx);
10800        });
10801    }
10802
10803    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
10804        let Some(project) = self.project.clone() else {
10805            return;
10806        };
10807        self.reload(project, window, cx)
10808            .detach_and_notify_err(window, cx);
10809    }
10810
10811    pub fn restore_file(
10812        &mut self,
10813        _: &::git::RestoreFile,
10814        window: &mut Window,
10815        cx: &mut Context<Self>,
10816    ) {
10817        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10818        let mut buffer_ids = HashSet::default();
10819        let snapshot = self.buffer().read(cx).snapshot(cx);
10820        for selection in self.selections.all::<usize>(&self.display_snapshot(cx)) {
10821            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
10822        }
10823
10824        let buffer = self.buffer().read(cx);
10825        let ranges = buffer_ids
10826            .into_iter()
10827            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
10828            .collect::<Vec<_>>();
10829
10830        self.restore_hunks_in_ranges(ranges, window, cx);
10831    }
10832
10833    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
10834        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10835        let selections = self
10836            .selections
10837            .all(&self.display_snapshot(cx))
10838            .into_iter()
10839            .map(|s| s.range())
10840            .collect();
10841        self.restore_hunks_in_ranges(selections, window, cx);
10842    }
10843
10844    pub fn restore_hunks_in_ranges(
10845        &mut self,
10846        ranges: Vec<Range<Point>>,
10847        window: &mut Window,
10848        cx: &mut Context<Editor>,
10849    ) {
10850        let mut revert_changes = HashMap::default();
10851        let chunk_by = self
10852            .snapshot(window, cx)
10853            .hunks_for_ranges(ranges)
10854            .into_iter()
10855            .chunk_by(|hunk| hunk.buffer_id);
10856        for (buffer_id, hunks) in &chunk_by {
10857            let hunks = hunks.collect::<Vec<_>>();
10858            for hunk in &hunks {
10859                self.prepare_restore_change(&mut revert_changes, hunk, cx);
10860            }
10861            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
10862        }
10863        drop(chunk_by);
10864        if !revert_changes.is_empty() {
10865            self.transact(window, cx, |editor, window, cx| {
10866                editor.restore(revert_changes, window, cx);
10867            });
10868        }
10869    }
10870
10871    pub fn status_for_buffer_id(&self, buffer_id: BufferId, cx: &App) -> Option<FileStatus> {
10872        if let Some(status) = self
10873            .addons
10874            .iter()
10875            .find_map(|(_, addon)| addon.override_status_for_buffer_id(buffer_id, cx))
10876        {
10877            return Some(status);
10878        }
10879        self.project
10880            .as_ref()?
10881            .read(cx)
10882            .status_for_buffer_id(buffer_id, cx)
10883    }
10884
10885    pub fn open_active_item_in_terminal(
10886        &mut self,
10887        _: &OpenInTerminal,
10888        window: &mut Window,
10889        cx: &mut Context<Self>,
10890    ) {
10891        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
10892            let project_path = buffer.read(cx).project_path(cx)?;
10893            let project = self.project()?.read(cx);
10894            let entry = project.entry_for_path(&project_path, cx)?;
10895            let parent = match &entry.canonical_path {
10896                Some(canonical_path) => canonical_path.to_path_buf(),
10897                None => project.absolute_path(&project_path, cx)?,
10898            }
10899            .parent()?
10900            .to_path_buf();
10901            Some(parent)
10902        }) {
10903            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
10904        }
10905    }
10906
10907    fn set_breakpoint_context_menu(
10908        &mut self,
10909        display_row: DisplayRow,
10910        position: Option<Anchor>,
10911        clicked_point: gpui::Point<Pixels>,
10912        window: &mut Window,
10913        cx: &mut Context<Self>,
10914    ) {
10915        let source = self
10916            .buffer
10917            .read(cx)
10918            .snapshot(cx)
10919            .anchor_before(Point::new(display_row.0, 0u32));
10920
10921        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
10922
10923        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
10924            self,
10925            source,
10926            clicked_point,
10927            context_menu,
10928            window,
10929            cx,
10930        );
10931    }
10932
10933    fn add_edit_breakpoint_block(
10934        &mut self,
10935        anchor: Anchor,
10936        breakpoint: &Breakpoint,
10937        edit_action: BreakpointPromptEditAction,
10938        window: &mut Window,
10939        cx: &mut Context<Self>,
10940    ) {
10941        let weak_editor = cx.weak_entity();
10942        let bp_prompt = cx.new(|cx| {
10943            BreakpointPromptEditor::new(
10944                weak_editor,
10945                anchor,
10946                breakpoint.clone(),
10947                edit_action,
10948                window,
10949                cx,
10950            )
10951        });
10952
10953        let height = bp_prompt.update(cx, |this, cx| {
10954            this.prompt
10955                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
10956        });
10957        let cloned_prompt = bp_prompt.clone();
10958        let blocks = vec![BlockProperties {
10959            style: BlockStyle::Sticky,
10960            placement: BlockPlacement::Above(anchor),
10961            height: Some(height),
10962            render: Arc::new(move |cx| {
10963                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
10964                cloned_prompt.clone().into_any_element()
10965            }),
10966            priority: 0,
10967        }];
10968
10969        let focus_handle = bp_prompt.focus_handle(cx);
10970        window.focus(&focus_handle);
10971
10972        let block_ids = self.insert_blocks(blocks, None, cx);
10973        bp_prompt.update(cx, |prompt, _| {
10974            prompt.add_block_ids(block_ids);
10975        });
10976    }
10977
10978    pub(crate) fn breakpoint_at_row(
10979        &self,
10980        row: u32,
10981        window: &mut Window,
10982        cx: &mut Context<Self>,
10983    ) -> Option<(Anchor, Breakpoint)> {
10984        let snapshot = self.snapshot(window, cx);
10985        let breakpoint_position = snapshot.buffer_snapshot().anchor_before(Point::new(row, 0));
10986
10987        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10988    }
10989
10990    pub(crate) fn breakpoint_at_anchor(
10991        &self,
10992        breakpoint_position: Anchor,
10993        snapshot: &EditorSnapshot,
10994        cx: &mut Context<Self>,
10995    ) -> Option<(Anchor, Breakpoint)> {
10996        let buffer = self
10997            .buffer
10998            .read(cx)
10999            .buffer_for_anchor(breakpoint_position, cx)?;
11000
11001        let enclosing_excerpt = breakpoint_position.excerpt_id;
11002        let buffer_snapshot = buffer.read(cx).snapshot();
11003
11004        let row = buffer_snapshot
11005            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
11006            .row;
11007
11008        let line_len = snapshot.buffer_snapshot().line_len(MultiBufferRow(row));
11009        let anchor_end = snapshot
11010            .buffer_snapshot()
11011            .anchor_after(Point::new(row, line_len));
11012
11013        self.breakpoint_store
11014            .as_ref()?
11015            .read_with(cx, |breakpoint_store, cx| {
11016                breakpoint_store
11017                    .breakpoints(
11018                        &buffer,
11019                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
11020                        &buffer_snapshot,
11021                        cx,
11022                    )
11023                    .next()
11024                    .and_then(|(bp, _)| {
11025                        let breakpoint_row = buffer_snapshot
11026                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
11027                            .row;
11028
11029                        if breakpoint_row == row {
11030                            snapshot
11031                                .buffer_snapshot()
11032                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
11033                                .map(|position| (position, bp.bp.clone()))
11034                        } else {
11035                            None
11036                        }
11037                    })
11038            })
11039    }
11040
11041    pub fn edit_log_breakpoint(
11042        &mut self,
11043        _: &EditLogBreakpoint,
11044        window: &mut Window,
11045        cx: &mut Context<Self>,
11046    ) {
11047        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11048            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
11049                message: None,
11050                state: BreakpointState::Enabled,
11051                condition: None,
11052                hit_condition: None,
11053            });
11054
11055            self.add_edit_breakpoint_block(
11056                anchor,
11057                &breakpoint,
11058                BreakpointPromptEditAction::Log,
11059                window,
11060                cx,
11061            );
11062        }
11063    }
11064
11065    fn breakpoints_at_cursors(
11066        &self,
11067        window: &mut Window,
11068        cx: &mut Context<Self>,
11069    ) -> Vec<(Anchor, Option<Breakpoint>)> {
11070        let snapshot = self.snapshot(window, cx);
11071        let cursors = self
11072            .selections
11073            .disjoint_anchors_arc()
11074            .iter()
11075            .map(|selection| {
11076                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot());
11077
11078                let breakpoint_position = self
11079                    .breakpoint_at_row(cursor_position.row, window, cx)
11080                    .map(|bp| bp.0)
11081                    .unwrap_or_else(|| {
11082                        snapshot
11083                            .display_snapshot
11084                            .buffer_snapshot()
11085                            .anchor_after(Point::new(cursor_position.row, 0))
11086                    });
11087
11088                let breakpoint = self
11089                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
11090                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
11091
11092                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
11093            })
11094            // 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.
11095            .collect::<HashMap<Anchor, _>>();
11096
11097        cursors.into_iter().collect()
11098    }
11099
11100    pub fn enable_breakpoint(
11101        &mut self,
11102        _: &crate::actions::EnableBreakpoint,
11103        window: &mut Window,
11104        cx: &mut Context<Self>,
11105    ) {
11106        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11107            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
11108                continue;
11109            };
11110            self.edit_breakpoint_at_anchor(
11111                anchor,
11112                breakpoint,
11113                BreakpointEditAction::InvertState,
11114                cx,
11115            );
11116        }
11117    }
11118
11119    pub fn disable_breakpoint(
11120        &mut self,
11121        _: &crate::actions::DisableBreakpoint,
11122        window: &mut Window,
11123        cx: &mut Context<Self>,
11124    ) {
11125        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11126            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
11127                continue;
11128            };
11129            self.edit_breakpoint_at_anchor(
11130                anchor,
11131                breakpoint,
11132                BreakpointEditAction::InvertState,
11133                cx,
11134            );
11135        }
11136    }
11137
11138    pub fn toggle_breakpoint(
11139        &mut self,
11140        _: &crate::actions::ToggleBreakpoint,
11141        window: &mut Window,
11142        cx: &mut Context<Self>,
11143    ) {
11144        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11145            if let Some(breakpoint) = breakpoint {
11146                self.edit_breakpoint_at_anchor(
11147                    anchor,
11148                    breakpoint,
11149                    BreakpointEditAction::Toggle,
11150                    cx,
11151                );
11152            } else {
11153                self.edit_breakpoint_at_anchor(
11154                    anchor,
11155                    Breakpoint::new_standard(),
11156                    BreakpointEditAction::Toggle,
11157                    cx,
11158                );
11159            }
11160        }
11161    }
11162
11163    pub fn edit_breakpoint_at_anchor(
11164        &mut self,
11165        breakpoint_position: Anchor,
11166        breakpoint: Breakpoint,
11167        edit_action: BreakpointEditAction,
11168        cx: &mut Context<Self>,
11169    ) {
11170        let Some(breakpoint_store) = &self.breakpoint_store else {
11171            return;
11172        };
11173
11174        let Some(buffer) = self
11175            .buffer
11176            .read(cx)
11177            .buffer_for_anchor(breakpoint_position, cx)
11178        else {
11179            return;
11180        };
11181
11182        breakpoint_store.update(cx, |breakpoint_store, cx| {
11183            breakpoint_store.toggle_breakpoint(
11184                buffer,
11185                BreakpointWithPosition {
11186                    position: breakpoint_position.text_anchor,
11187                    bp: breakpoint,
11188                },
11189                edit_action,
11190                cx,
11191            );
11192        });
11193
11194        cx.notify();
11195    }
11196
11197    #[cfg(any(test, feature = "test-support"))]
11198    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
11199        self.breakpoint_store.clone()
11200    }
11201
11202    pub fn prepare_restore_change(
11203        &self,
11204        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
11205        hunk: &MultiBufferDiffHunk,
11206        cx: &mut App,
11207    ) -> Option<()> {
11208        if hunk.is_created_file() {
11209            return None;
11210        }
11211        let buffer = self.buffer.read(cx);
11212        let diff = buffer.diff_for(hunk.buffer_id)?;
11213        let buffer = buffer.buffer(hunk.buffer_id)?;
11214        let buffer = buffer.read(cx);
11215        let original_text = diff
11216            .read(cx)
11217            .base_text()
11218            .as_rope()
11219            .slice(hunk.diff_base_byte_range.clone());
11220        let buffer_snapshot = buffer.snapshot();
11221        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
11222        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
11223            probe
11224                .0
11225                .start
11226                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
11227                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
11228        }) {
11229            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
11230            Some(())
11231        } else {
11232            None
11233        }
11234    }
11235
11236    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
11237        self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())
11238    }
11239
11240    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
11241        self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut rand::rng()))
11242    }
11243
11244    fn manipulate_lines<M>(
11245        &mut self,
11246        window: &mut Window,
11247        cx: &mut Context<Self>,
11248        mut manipulate: M,
11249    ) where
11250        M: FnMut(&str) -> LineManipulationResult,
11251    {
11252        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11253
11254        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11255        let buffer = self.buffer.read(cx).snapshot(cx);
11256
11257        let mut edits = Vec::new();
11258
11259        let selections = self.selections.all::<Point>(&display_map);
11260        let mut selections = selections.iter().peekable();
11261        let mut contiguous_row_selections = Vec::new();
11262        let mut new_selections = Vec::new();
11263        let mut added_lines = 0;
11264        let mut removed_lines = 0;
11265
11266        while let Some(selection) = selections.next() {
11267            let (start_row, end_row) = consume_contiguous_rows(
11268                &mut contiguous_row_selections,
11269                selection,
11270                &display_map,
11271                &mut selections,
11272            );
11273
11274            let start_point = Point::new(start_row.0, 0);
11275            let end_point = Point::new(
11276                end_row.previous_row().0,
11277                buffer.line_len(end_row.previous_row()),
11278            );
11279            let text = buffer
11280                .text_for_range(start_point..end_point)
11281                .collect::<String>();
11282
11283            let LineManipulationResult {
11284                new_text,
11285                line_count_before,
11286                line_count_after,
11287            } = manipulate(&text);
11288
11289            edits.push((start_point..end_point, new_text));
11290
11291            // Selections must change based on added and removed line count
11292            let start_row =
11293                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
11294            let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);
11295            new_selections.push(Selection {
11296                id: selection.id,
11297                start: start_row,
11298                end: end_row,
11299                goal: SelectionGoal::None,
11300                reversed: selection.reversed,
11301            });
11302
11303            if line_count_after > line_count_before {
11304                added_lines += line_count_after - line_count_before;
11305            } else if line_count_before > line_count_after {
11306                removed_lines += line_count_before - line_count_after;
11307            }
11308        }
11309
11310        self.transact(window, cx, |this, window, cx| {
11311            let buffer = this.buffer.update(cx, |buffer, cx| {
11312                buffer.edit(edits, None, cx);
11313                buffer.snapshot(cx)
11314            });
11315
11316            // Recalculate offsets on newly edited buffer
11317            let new_selections = new_selections
11318                .iter()
11319                .map(|s| {
11320                    let start_point = Point::new(s.start.0, 0);
11321                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
11322                    Selection {
11323                        id: s.id,
11324                        start: buffer.point_to_offset(start_point),
11325                        end: buffer.point_to_offset(end_point),
11326                        goal: s.goal,
11327                        reversed: s.reversed,
11328                    }
11329                })
11330                .collect();
11331
11332            this.change_selections(Default::default(), window, cx, |s| {
11333                s.select(new_selections);
11334            });
11335
11336            this.request_autoscroll(Autoscroll::fit(), cx);
11337        });
11338    }
11339
11340    fn manipulate_immutable_lines<Fn>(
11341        &mut self,
11342        window: &mut Window,
11343        cx: &mut Context<Self>,
11344        mut callback: Fn,
11345    ) where
11346        Fn: FnMut(&mut Vec<&str>),
11347    {
11348        self.manipulate_lines(window, cx, |text| {
11349            let mut lines: Vec<&str> = text.split('\n').collect();
11350            let line_count_before = lines.len();
11351
11352            callback(&mut lines);
11353
11354            LineManipulationResult {
11355                new_text: lines.join("\n"),
11356                line_count_before,
11357                line_count_after: lines.len(),
11358            }
11359        });
11360    }
11361
11362    fn manipulate_mutable_lines<Fn>(
11363        &mut self,
11364        window: &mut Window,
11365        cx: &mut Context<Self>,
11366        mut callback: Fn,
11367    ) where
11368        Fn: FnMut(&mut Vec<Cow<'_, str>>),
11369    {
11370        self.manipulate_lines(window, cx, |text| {
11371            let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
11372            let line_count_before = lines.len();
11373
11374            callback(&mut lines);
11375
11376            LineManipulationResult {
11377                new_text: lines.join("\n"),
11378                line_count_before,
11379                line_count_after: lines.len(),
11380            }
11381        });
11382    }
11383
11384    pub fn convert_indentation_to_spaces(
11385        &mut self,
11386        _: &ConvertIndentationToSpaces,
11387        window: &mut Window,
11388        cx: &mut Context<Self>,
11389    ) {
11390        let settings = self.buffer.read(cx).language_settings(cx);
11391        let tab_size = settings.tab_size.get() as usize;
11392
11393        self.manipulate_mutable_lines(window, cx, |lines| {
11394            // Allocates a reasonably sized scratch buffer once for the whole loop
11395            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11396            // Avoids recomputing spaces that could be inserted many times
11397            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11398                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11399                .collect();
11400
11401            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11402                let mut chars = line.as_ref().chars();
11403                let mut col = 0;
11404                let mut changed = false;
11405
11406                for ch in chars.by_ref() {
11407                    match ch {
11408                        ' ' => {
11409                            reindented_line.push(' ');
11410                            col += 1;
11411                        }
11412                        '\t' => {
11413                            // \t are converted to spaces depending on the current column
11414                            let spaces_len = tab_size - (col % tab_size);
11415                            reindented_line.extend(&space_cache[spaces_len - 1]);
11416                            col += spaces_len;
11417                            changed = true;
11418                        }
11419                        _ => {
11420                            // If we dont append before break, the character is consumed
11421                            reindented_line.push(ch);
11422                            break;
11423                        }
11424                    }
11425                }
11426
11427                if !changed {
11428                    reindented_line.clear();
11429                    continue;
11430                }
11431                // Append the rest of the line and replace old reference with new one
11432                reindented_line.extend(chars);
11433                *line = Cow::Owned(reindented_line.clone());
11434                reindented_line.clear();
11435            }
11436        });
11437    }
11438
11439    pub fn convert_indentation_to_tabs(
11440        &mut self,
11441        _: &ConvertIndentationToTabs,
11442        window: &mut Window,
11443        cx: &mut Context<Self>,
11444    ) {
11445        let settings = self.buffer.read(cx).language_settings(cx);
11446        let tab_size = settings.tab_size.get() as usize;
11447
11448        self.manipulate_mutable_lines(window, cx, |lines| {
11449            // Allocates a reasonably sized buffer once for the whole loop
11450            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11451            // Avoids recomputing spaces that could be inserted many times
11452            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11453                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11454                .collect();
11455
11456            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11457                let mut chars = line.chars();
11458                let mut spaces_count = 0;
11459                let mut first_non_indent_char = None;
11460                let mut changed = false;
11461
11462                for ch in chars.by_ref() {
11463                    match ch {
11464                        ' ' => {
11465                            // Keep track of spaces. Append \t when we reach tab_size
11466                            spaces_count += 1;
11467                            changed = true;
11468                            if spaces_count == tab_size {
11469                                reindented_line.push('\t');
11470                                spaces_count = 0;
11471                            }
11472                        }
11473                        '\t' => {
11474                            reindented_line.push('\t');
11475                            spaces_count = 0;
11476                        }
11477                        _ => {
11478                            // Dont append it yet, we might have remaining spaces
11479                            first_non_indent_char = Some(ch);
11480                            break;
11481                        }
11482                    }
11483                }
11484
11485                if !changed {
11486                    reindented_line.clear();
11487                    continue;
11488                }
11489                // Remaining spaces that didn't make a full tab stop
11490                if spaces_count > 0 {
11491                    reindented_line.extend(&space_cache[spaces_count - 1]);
11492                }
11493                // If we consume an extra character that was not indentation, add it back
11494                if let Some(extra_char) = first_non_indent_char {
11495                    reindented_line.push(extra_char);
11496                }
11497                // Append the rest of the line and replace old reference with new one
11498                reindented_line.extend(chars);
11499                *line = Cow::Owned(reindented_line.clone());
11500                reindented_line.clear();
11501            }
11502        });
11503    }
11504
11505    pub fn convert_to_upper_case(
11506        &mut self,
11507        _: &ConvertToUpperCase,
11508        window: &mut Window,
11509        cx: &mut Context<Self>,
11510    ) {
11511        self.manipulate_text(window, cx, |text| text.to_uppercase())
11512    }
11513
11514    pub fn convert_to_lower_case(
11515        &mut self,
11516        _: &ConvertToLowerCase,
11517        window: &mut Window,
11518        cx: &mut Context<Self>,
11519    ) {
11520        self.manipulate_text(window, cx, |text| text.to_lowercase())
11521    }
11522
11523    pub fn convert_to_title_case(
11524        &mut self,
11525        _: &ConvertToTitleCase,
11526        window: &mut Window,
11527        cx: &mut Context<Self>,
11528    ) {
11529        self.manipulate_text(window, cx, |text| {
11530            text.split('\n')
11531                .map(|line| line.to_case(Case::Title))
11532                .join("\n")
11533        })
11534    }
11535
11536    pub fn convert_to_snake_case(
11537        &mut self,
11538        _: &ConvertToSnakeCase,
11539        window: &mut Window,
11540        cx: &mut Context<Self>,
11541    ) {
11542        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
11543    }
11544
11545    pub fn convert_to_kebab_case(
11546        &mut self,
11547        _: &ConvertToKebabCase,
11548        window: &mut Window,
11549        cx: &mut Context<Self>,
11550    ) {
11551        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
11552    }
11553
11554    pub fn convert_to_upper_camel_case(
11555        &mut self,
11556        _: &ConvertToUpperCamelCase,
11557        window: &mut Window,
11558        cx: &mut Context<Self>,
11559    ) {
11560        self.manipulate_text(window, cx, |text| {
11561            text.split('\n')
11562                .map(|line| line.to_case(Case::UpperCamel))
11563                .join("\n")
11564        })
11565    }
11566
11567    pub fn convert_to_lower_camel_case(
11568        &mut self,
11569        _: &ConvertToLowerCamelCase,
11570        window: &mut Window,
11571        cx: &mut Context<Self>,
11572    ) {
11573        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
11574    }
11575
11576    pub fn convert_to_opposite_case(
11577        &mut self,
11578        _: &ConvertToOppositeCase,
11579        window: &mut Window,
11580        cx: &mut Context<Self>,
11581    ) {
11582        self.manipulate_text(window, cx, |text| {
11583            text.chars()
11584                .fold(String::with_capacity(text.len()), |mut t, c| {
11585                    if c.is_uppercase() {
11586                        t.extend(c.to_lowercase());
11587                    } else {
11588                        t.extend(c.to_uppercase());
11589                    }
11590                    t
11591                })
11592        })
11593    }
11594
11595    pub fn convert_to_sentence_case(
11596        &mut self,
11597        _: &ConvertToSentenceCase,
11598        window: &mut Window,
11599        cx: &mut Context<Self>,
11600    ) {
11601        self.manipulate_text(window, cx, |text| text.to_case(Case::Sentence))
11602    }
11603
11604    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
11605        self.manipulate_text(window, cx, |text| {
11606            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
11607            if has_upper_case_characters {
11608                text.to_lowercase()
11609            } else {
11610                text.to_uppercase()
11611            }
11612        })
11613    }
11614
11615    pub fn convert_to_rot13(
11616        &mut self,
11617        _: &ConvertToRot13,
11618        window: &mut Window,
11619        cx: &mut Context<Self>,
11620    ) {
11621        self.manipulate_text(window, cx, |text| {
11622            text.chars()
11623                .map(|c| match c {
11624                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
11625                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
11626                    _ => c,
11627                })
11628                .collect()
11629        })
11630    }
11631
11632    pub fn convert_to_rot47(
11633        &mut self,
11634        _: &ConvertToRot47,
11635        window: &mut Window,
11636        cx: &mut Context<Self>,
11637    ) {
11638        self.manipulate_text(window, cx, |text| {
11639            text.chars()
11640                .map(|c| {
11641                    let code_point = c as u32;
11642                    if code_point >= 33 && code_point <= 126 {
11643                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
11644                    }
11645                    c
11646                })
11647                .collect()
11648        })
11649    }
11650
11651    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
11652    where
11653        Fn: FnMut(&str) -> String,
11654    {
11655        let buffer = self.buffer.read(cx).snapshot(cx);
11656
11657        let mut new_selections = Vec::new();
11658        let mut edits = Vec::new();
11659        let mut selection_adjustment = 0i32;
11660
11661        for selection in self.selections.all_adjusted(&self.display_snapshot(cx)) {
11662            let selection_is_empty = selection.is_empty();
11663
11664            let (start, end) = if selection_is_empty {
11665                let (word_range, _) = buffer.surrounding_word(selection.start, None);
11666                (word_range.start, word_range.end)
11667            } else {
11668                (
11669                    buffer.point_to_offset(selection.start),
11670                    buffer.point_to_offset(selection.end),
11671                )
11672            };
11673
11674            let text = buffer.text_for_range(start..end).collect::<String>();
11675            let old_length = text.len() as i32;
11676            let text = callback(&text);
11677
11678            new_selections.push(Selection {
11679                start: (start as i32 - selection_adjustment) as usize,
11680                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
11681                goal: SelectionGoal::None,
11682                id: selection.id,
11683                reversed: selection.reversed,
11684            });
11685
11686            selection_adjustment += old_length - text.len() as i32;
11687
11688            edits.push((start..end, text));
11689        }
11690
11691        self.transact(window, cx, |this, window, cx| {
11692            this.buffer.update(cx, |buffer, cx| {
11693                buffer.edit(edits, None, cx);
11694            });
11695
11696            this.change_selections(Default::default(), window, cx, |s| {
11697                s.select(new_selections);
11698            });
11699
11700            this.request_autoscroll(Autoscroll::fit(), cx);
11701        });
11702    }
11703
11704    pub fn move_selection_on_drop(
11705        &mut self,
11706        selection: &Selection<Anchor>,
11707        target: DisplayPoint,
11708        is_cut: bool,
11709        window: &mut Window,
11710        cx: &mut Context<Self>,
11711    ) {
11712        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11713        let buffer = display_map.buffer_snapshot();
11714        let mut edits = Vec::new();
11715        let insert_point = display_map
11716            .clip_point(target, Bias::Left)
11717            .to_point(&display_map);
11718        let text = buffer
11719            .text_for_range(selection.start..selection.end)
11720            .collect::<String>();
11721        if is_cut {
11722            edits.push(((selection.start..selection.end), String::new()));
11723        }
11724        let insert_anchor = buffer.anchor_before(insert_point);
11725        edits.push(((insert_anchor..insert_anchor), text));
11726        let last_edit_start = insert_anchor.bias_left(buffer);
11727        let last_edit_end = insert_anchor.bias_right(buffer);
11728        self.transact(window, cx, |this, window, cx| {
11729            this.buffer.update(cx, |buffer, cx| {
11730                buffer.edit(edits, None, cx);
11731            });
11732            this.change_selections(Default::default(), window, cx, |s| {
11733                s.select_anchor_ranges([last_edit_start..last_edit_end]);
11734            });
11735        });
11736    }
11737
11738    pub fn clear_selection_drag_state(&mut self) {
11739        self.selection_drag_state = SelectionDragState::None;
11740    }
11741
11742    pub fn duplicate(
11743        &mut self,
11744        upwards: bool,
11745        whole_lines: bool,
11746        window: &mut Window,
11747        cx: &mut Context<Self>,
11748    ) {
11749        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11750
11751        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11752        let buffer = display_map.buffer_snapshot();
11753        let selections = self.selections.all::<Point>(&display_map);
11754
11755        let mut edits = Vec::new();
11756        let mut selections_iter = selections.iter().peekable();
11757        while let Some(selection) = selections_iter.next() {
11758            let mut rows = selection.spanned_rows(false, &display_map);
11759            // duplicate line-wise
11760            if whole_lines || selection.start == selection.end {
11761                // Avoid duplicating the same lines twice.
11762                while let Some(next_selection) = selections_iter.peek() {
11763                    let next_rows = next_selection.spanned_rows(false, &display_map);
11764                    if next_rows.start < rows.end {
11765                        rows.end = next_rows.end;
11766                        selections_iter.next().unwrap();
11767                    } else {
11768                        break;
11769                    }
11770                }
11771
11772                // Copy the text from the selected row region and splice it either at the start
11773                // or end of the region.
11774                let start = Point::new(rows.start.0, 0);
11775                let end = Point::new(
11776                    rows.end.previous_row().0,
11777                    buffer.line_len(rows.end.previous_row()),
11778                );
11779
11780                let mut text = buffer.text_for_range(start..end).collect::<String>();
11781
11782                let insert_location = if upwards {
11783                    // When duplicating upward, we need to insert before the current line.
11784                    // If we're on the last line and it doesn't end with a newline,
11785                    // we need to add a newline before the duplicated content.
11786                    let needs_leading_newline = rows.end.0 >= buffer.max_point().row
11787                        && buffer.max_point().column > 0
11788                        && !text.ends_with('\n');
11789
11790                    if needs_leading_newline {
11791                        text.insert(0, '\n');
11792                        end
11793                    } else {
11794                        text.push('\n');
11795                        Point::new(rows.start.0, 0)
11796                    }
11797                } else {
11798                    text.push('\n');
11799                    start
11800                };
11801                edits.push((insert_location..insert_location, text));
11802            } else {
11803                // duplicate character-wise
11804                let start = selection.start;
11805                let end = selection.end;
11806                let text = buffer.text_for_range(start..end).collect::<String>();
11807                edits.push((selection.end..selection.end, text));
11808            }
11809        }
11810
11811        self.transact(window, cx, |this, window, cx| {
11812            this.buffer.update(cx, |buffer, cx| {
11813                buffer.edit(edits, None, cx);
11814            });
11815
11816            // When duplicating upward with whole lines, move the cursor to the duplicated line
11817            if upwards && whole_lines {
11818                let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
11819
11820                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
11821                    let mut new_ranges = Vec::new();
11822                    let selections = s.all::<Point>(&display_map);
11823                    let mut selections_iter = selections.iter().peekable();
11824
11825                    while let Some(first_selection) = selections_iter.next() {
11826                        // Group contiguous selections together to find the total row span
11827                        let mut group_selections = vec![first_selection];
11828                        let mut rows = first_selection.spanned_rows(false, &display_map);
11829
11830                        while let Some(next_selection) = selections_iter.peek() {
11831                            let next_rows = next_selection.spanned_rows(false, &display_map);
11832                            if next_rows.start < rows.end {
11833                                rows.end = next_rows.end;
11834                                group_selections.push(selections_iter.next().unwrap());
11835                            } else {
11836                                break;
11837                            }
11838                        }
11839
11840                        let row_count = rows.end.0 - rows.start.0;
11841
11842                        // Move all selections in this group up by the total number of duplicated rows
11843                        for selection in group_selections {
11844                            let new_start = Point::new(
11845                                selection.start.row.saturating_sub(row_count),
11846                                selection.start.column,
11847                            );
11848
11849                            let new_end = Point::new(
11850                                selection.end.row.saturating_sub(row_count),
11851                                selection.end.column,
11852                            );
11853
11854                            new_ranges.push(new_start..new_end);
11855                        }
11856                    }
11857
11858                    s.select_ranges(new_ranges);
11859                });
11860            }
11861
11862            this.request_autoscroll(Autoscroll::fit(), cx);
11863        });
11864    }
11865
11866    pub fn duplicate_line_up(
11867        &mut self,
11868        _: &DuplicateLineUp,
11869        window: &mut Window,
11870        cx: &mut Context<Self>,
11871    ) {
11872        self.duplicate(true, true, window, cx);
11873    }
11874
11875    pub fn duplicate_line_down(
11876        &mut self,
11877        _: &DuplicateLineDown,
11878        window: &mut Window,
11879        cx: &mut Context<Self>,
11880    ) {
11881        self.duplicate(false, true, window, cx);
11882    }
11883
11884    pub fn duplicate_selection(
11885        &mut self,
11886        _: &DuplicateSelection,
11887        window: &mut Window,
11888        cx: &mut Context<Self>,
11889    ) {
11890        self.duplicate(false, false, window, cx);
11891    }
11892
11893    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
11894        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11895        if self.mode.is_single_line() {
11896            cx.propagate();
11897            return;
11898        }
11899
11900        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11901        let buffer = self.buffer.read(cx).snapshot(cx);
11902
11903        let mut edits = Vec::new();
11904        let mut unfold_ranges = Vec::new();
11905        let mut refold_creases = Vec::new();
11906
11907        let selections = self.selections.all::<Point>(&display_map);
11908        let mut selections = selections.iter().peekable();
11909        let mut contiguous_row_selections = Vec::new();
11910        let mut new_selections = Vec::new();
11911
11912        while let Some(selection) = selections.next() {
11913            // Find all the selections that span a contiguous row range
11914            let (start_row, end_row) = consume_contiguous_rows(
11915                &mut contiguous_row_selections,
11916                selection,
11917                &display_map,
11918                &mut selections,
11919            );
11920
11921            // Move the text spanned by the row range to be before the line preceding the row range
11922            if start_row.0 > 0 {
11923                let range_to_move = Point::new(
11924                    start_row.previous_row().0,
11925                    buffer.line_len(start_row.previous_row()),
11926                )
11927                    ..Point::new(
11928                        end_row.previous_row().0,
11929                        buffer.line_len(end_row.previous_row()),
11930                    );
11931                let insertion_point = display_map
11932                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
11933                    .0;
11934
11935                // Don't move lines across excerpts
11936                if buffer
11937                    .excerpt_containing(insertion_point..range_to_move.end)
11938                    .is_some()
11939                {
11940                    let text = buffer
11941                        .text_for_range(range_to_move.clone())
11942                        .flat_map(|s| s.chars())
11943                        .skip(1)
11944                        .chain(['\n'])
11945                        .collect::<String>();
11946
11947                    edits.push((
11948                        buffer.anchor_after(range_to_move.start)
11949                            ..buffer.anchor_before(range_to_move.end),
11950                        String::new(),
11951                    ));
11952                    let insertion_anchor = buffer.anchor_after(insertion_point);
11953                    edits.push((insertion_anchor..insertion_anchor, text));
11954
11955                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
11956
11957                    // Move selections up
11958                    new_selections.extend(contiguous_row_selections.drain(..).map(
11959                        |mut selection| {
11960                            selection.start.row -= row_delta;
11961                            selection.end.row -= row_delta;
11962                            selection
11963                        },
11964                    ));
11965
11966                    // Move folds up
11967                    unfold_ranges.push(range_to_move.clone());
11968                    for fold in display_map.folds_in_range(
11969                        buffer.anchor_before(range_to_move.start)
11970                            ..buffer.anchor_after(range_to_move.end),
11971                    ) {
11972                        let mut start = fold.range.start.to_point(&buffer);
11973                        let mut end = fold.range.end.to_point(&buffer);
11974                        start.row -= row_delta;
11975                        end.row -= row_delta;
11976                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11977                    }
11978                }
11979            }
11980
11981            // If we didn't move line(s), preserve the existing selections
11982            new_selections.append(&mut contiguous_row_selections);
11983        }
11984
11985        self.transact(window, cx, |this, window, cx| {
11986            this.unfold_ranges(&unfold_ranges, true, true, cx);
11987            this.buffer.update(cx, |buffer, cx| {
11988                for (range, text) in edits {
11989                    buffer.edit([(range, text)], None, cx);
11990                }
11991            });
11992            this.fold_creases(refold_creases, true, window, cx);
11993            this.change_selections(Default::default(), window, cx, |s| {
11994                s.select(new_selections);
11995            })
11996        });
11997    }
11998
11999    pub fn move_line_down(
12000        &mut self,
12001        _: &MoveLineDown,
12002        window: &mut Window,
12003        cx: &mut Context<Self>,
12004    ) {
12005        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12006        if self.mode.is_single_line() {
12007            cx.propagate();
12008            return;
12009        }
12010
12011        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12012        let buffer = self.buffer.read(cx).snapshot(cx);
12013
12014        let mut edits = Vec::new();
12015        let mut unfold_ranges = Vec::new();
12016        let mut refold_creases = Vec::new();
12017
12018        let selections = self.selections.all::<Point>(&display_map);
12019        let mut selections = selections.iter().peekable();
12020        let mut contiguous_row_selections = Vec::new();
12021        let mut new_selections = Vec::new();
12022
12023        while let Some(selection) = selections.next() {
12024            // Find all the selections that span a contiguous row range
12025            let (start_row, end_row) = consume_contiguous_rows(
12026                &mut contiguous_row_selections,
12027                selection,
12028                &display_map,
12029                &mut selections,
12030            );
12031
12032            // Move the text spanned by the row range to be after the last line of the row range
12033            if end_row.0 <= buffer.max_point().row {
12034                let range_to_move =
12035                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
12036                let insertion_point = display_map
12037                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
12038                    .0;
12039
12040                // Don't move lines across excerpt boundaries
12041                if buffer
12042                    .excerpt_containing(range_to_move.start..insertion_point)
12043                    .is_some()
12044                {
12045                    let mut text = String::from("\n");
12046                    text.extend(buffer.text_for_range(range_to_move.clone()));
12047                    text.pop(); // Drop trailing newline
12048                    edits.push((
12049                        buffer.anchor_after(range_to_move.start)
12050                            ..buffer.anchor_before(range_to_move.end),
12051                        String::new(),
12052                    ));
12053                    let insertion_anchor = buffer.anchor_after(insertion_point);
12054                    edits.push((insertion_anchor..insertion_anchor, text));
12055
12056                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
12057
12058                    // Move selections down
12059                    new_selections.extend(contiguous_row_selections.drain(..).map(
12060                        |mut selection| {
12061                            selection.start.row += row_delta;
12062                            selection.end.row += row_delta;
12063                            selection
12064                        },
12065                    ));
12066
12067                    // Move folds down
12068                    unfold_ranges.push(range_to_move.clone());
12069                    for fold in display_map.folds_in_range(
12070                        buffer.anchor_before(range_to_move.start)
12071                            ..buffer.anchor_after(range_to_move.end),
12072                    ) {
12073                        let mut start = fold.range.start.to_point(&buffer);
12074                        let mut end = fold.range.end.to_point(&buffer);
12075                        start.row += row_delta;
12076                        end.row += row_delta;
12077                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
12078                    }
12079                }
12080            }
12081
12082            // If we didn't move line(s), preserve the existing selections
12083            new_selections.append(&mut contiguous_row_selections);
12084        }
12085
12086        self.transact(window, cx, |this, window, cx| {
12087            this.unfold_ranges(&unfold_ranges, true, true, cx);
12088            this.buffer.update(cx, |buffer, cx| {
12089                for (range, text) in edits {
12090                    buffer.edit([(range, text)], None, cx);
12091                }
12092            });
12093            this.fold_creases(refold_creases, true, window, cx);
12094            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
12095        });
12096    }
12097
12098    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
12099        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12100        let text_layout_details = &self.text_layout_details(window);
12101        self.transact(window, cx, |this, window, cx| {
12102            let edits = this.change_selections(Default::default(), window, cx, |s| {
12103                let mut edits: Vec<(Range<usize>, String)> = Default::default();
12104                s.move_with(|display_map, selection| {
12105                    if !selection.is_empty() {
12106                        return;
12107                    }
12108
12109                    let mut head = selection.head();
12110                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
12111                    if head.column() == display_map.line_len(head.row()) {
12112                        transpose_offset = display_map
12113                            .buffer_snapshot()
12114                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
12115                    }
12116
12117                    if transpose_offset == 0 {
12118                        return;
12119                    }
12120
12121                    *head.column_mut() += 1;
12122                    head = display_map.clip_point(head, Bias::Right);
12123                    let goal = SelectionGoal::HorizontalPosition(
12124                        display_map
12125                            .x_for_display_point(head, text_layout_details)
12126                            .into(),
12127                    );
12128                    selection.collapse_to(head, goal);
12129
12130                    let transpose_start = display_map
12131                        .buffer_snapshot()
12132                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
12133                    if edits.last().is_none_or(|e| e.0.end <= transpose_start) {
12134                        let transpose_end = display_map
12135                            .buffer_snapshot()
12136                            .clip_offset(transpose_offset + 1, Bias::Right);
12137                        if let Some(ch) = display_map
12138                            .buffer_snapshot()
12139                            .chars_at(transpose_start)
12140                            .next()
12141                        {
12142                            edits.push((transpose_start..transpose_offset, String::new()));
12143                            edits.push((transpose_end..transpose_end, ch.to_string()));
12144                        }
12145                    }
12146                });
12147                edits
12148            });
12149            this.buffer
12150                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12151            let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
12152            this.change_selections(Default::default(), window, cx, |s| {
12153                s.select(selections);
12154            });
12155        });
12156    }
12157
12158    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
12159        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12160        if self.mode.is_single_line() {
12161            cx.propagate();
12162            return;
12163        }
12164
12165        self.rewrap_impl(RewrapOptions::default(), cx)
12166    }
12167
12168    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
12169        let buffer = self.buffer.read(cx).snapshot(cx);
12170        let selections = self.selections.all::<Point>(&self.display_snapshot(cx));
12171
12172        #[derive(Clone, Debug, PartialEq)]
12173        enum CommentFormat {
12174            /// single line comment, with prefix for line
12175            Line(String),
12176            /// single line within a block comment, with prefix for line
12177            BlockLine(String),
12178            /// a single line of a block comment that includes the initial delimiter
12179            BlockCommentWithStart(BlockCommentConfig),
12180            /// a single line of a block comment that includes the ending delimiter
12181            BlockCommentWithEnd(BlockCommentConfig),
12182        }
12183
12184        // Split selections to respect paragraph, indent, and comment prefix boundaries.
12185        let wrap_ranges = selections.into_iter().flat_map(|selection| {
12186            let mut non_blank_rows_iter = (selection.start.row..=selection.end.row)
12187                .filter(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
12188                .peekable();
12189
12190            let first_row = if let Some(&row) = non_blank_rows_iter.peek() {
12191                row
12192            } else {
12193                return Vec::new();
12194            };
12195
12196            let language_settings = buffer.language_settings_at(selection.head(), cx);
12197            let language_scope = buffer.language_scope_at(selection.head());
12198
12199            let indent_and_prefix_for_row =
12200                |row: u32| -> (IndentSize, Option<CommentFormat>, Option<String>) {
12201                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
12202                    let (comment_prefix, rewrap_prefix) = if let Some(language_scope) =
12203                        &language_scope
12204                    {
12205                        let indent_end = Point::new(row, indent.len);
12206                        let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
12207                        let line_text_after_indent = buffer
12208                            .text_for_range(indent_end..line_end)
12209                            .collect::<String>();
12210
12211                        let is_within_comment_override = buffer
12212                            .language_scope_at(indent_end)
12213                            .is_some_and(|scope| scope.override_name() == Some("comment"));
12214                        let comment_delimiters = if is_within_comment_override {
12215                            // we are within a comment syntax node, but we don't
12216                            // yet know what kind of comment: block, doc or line
12217                            match (
12218                                language_scope.documentation_comment(),
12219                                language_scope.block_comment(),
12220                            ) {
12221                                (Some(config), _) | (_, Some(config))
12222                                    if buffer.contains_str_at(indent_end, &config.start) =>
12223                                {
12224                                    Some(CommentFormat::BlockCommentWithStart(config.clone()))
12225                                }
12226                                (Some(config), _) | (_, Some(config))
12227                                    if line_text_after_indent.ends_with(config.end.as_ref()) =>
12228                                {
12229                                    Some(CommentFormat::BlockCommentWithEnd(config.clone()))
12230                                }
12231                                (Some(config), _) | (_, Some(config))
12232                                    if buffer.contains_str_at(indent_end, &config.prefix) =>
12233                                {
12234                                    Some(CommentFormat::BlockLine(config.prefix.to_string()))
12235                                }
12236                                (_, _) => language_scope
12237                                    .line_comment_prefixes()
12238                                    .iter()
12239                                    .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12240                                    .map(|prefix| CommentFormat::Line(prefix.to_string())),
12241                            }
12242                        } else {
12243                            // we not in an overridden comment node, but we may
12244                            // be within a non-overridden line comment node
12245                            language_scope
12246                                .line_comment_prefixes()
12247                                .iter()
12248                                .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12249                                .map(|prefix| CommentFormat::Line(prefix.to_string()))
12250                        };
12251
12252                        let rewrap_prefix = language_scope
12253                            .rewrap_prefixes()
12254                            .iter()
12255                            .find_map(|prefix_regex| {
12256                                prefix_regex.find(&line_text_after_indent).map(|mat| {
12257                                    if mat.start() == 0 {
12258                                        Some(mat.as_str().to_string())
12259                                    } else {
12260                                        None
12261                                    }
12262                                })
12263                            })
12264                            .flatten();
12265                        (comment_delimiters, rewrap_prefix)
12266                    } else {
12267                        (None, None)
12268                    };
12269                    (indent, comment_prefix, rewrap_prefix)
12270                };
12271
12272            let mut ranges = Vec::new();
12273            let from_empty_selection = selection.is_empty();
12274
12275            let mut current_range_start = first_row;
12276            let mut prev_row = first_row;
12277            let (
12278                mut current_range_indent,
12279                mut current_range_comment_delimiters,
12280                mut current_range_rewrap_prefix,
12281            ) = indent_and_prefix_for_row(first_row);
12282
12283            for row in non_blank_rows_iter.skip(1) {
12284                let has_paragraph_break = row > prev_row + 1;
12285
12286                let (row_indent, row_comment_delimiters, row_rewrap_prefix) =
12287                    indent_and_prefix_for_row(row);
12288
12289                let has_indent_change = row_indent != current_range_indent;
12290                let has_comment_change = row_comment_delimiters != current_range_comment_delimiters;
12291
12292                let has_boundary_change = has_comment_change
12293                    || row_rewrap_prefix.is_some()
12294                    || (has_indent_change && current_range_comment_delimiters.is_some());
12295
12296                if has_paragraph_break || has_boundary_change {
12297                    ranges.push((
12298                        language_settings.clone(),
12299                        Point::new(current_range_start, 0)
12300                            ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12301                        current_range_indent,
12302                        current_range_comment_delimiters.clone(),
12303                        current_range_rewrap_prefix.clone(),
12304                        from_empty_selection,
12305                    ));
12306                    current_range_start = row;
12307                    current_range_indent = row_indent;
12308                    current_range_comment_delimiters = row_comment_delimiters;
12309                    current_range_rewrap_prefix = row_rewrap_prefix;
12310                }
12311                prev_row = row;
12312            }
12313
12314            ranges.push((
12315                language_settings.clone(),
12316                Point::new(current_range_start, 0)
12317                    ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12318                current_range_indent,
12319                current_range_comment_delimiters,
12320                current_range_rewrap_prefix,
12321                from_empty_selection,
12322            ));
12323
12324            ranges
12325        });
12326
12327        let mut edits = Vec::new();
12328        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
12329
12330        for (
12331            language_settings,
12332            wrap_range,
12333            mut indent_size,
12334            comment_prefix,
12335            rewrap_prefix,
12336            from_empty_selection,
12337        ) in wrap_ranges
12338        {
12339            let mut start_row = wrap_range.start.row;
12340            let mut end_row = wrap_range.end.row;
12341
12342            // Skip selections that overlap with a range that has already been rewrapped.
12343            let selection_range = start_row..end_row;
12344            if rewrapped_row_ranges
12345                .iter()
12346                .any(|range| range.overlaps(&selection_range))
12347            {
12348                continue;
12349            }
12350
12351            let tab_size = language_settings.tab_size;
12352
12353            let (line_prefix, inside_comment) = match &comment_prefix {
12354                Some(CommentFormat::Line(prefix) | CommentFormat::BlockLine(prefix)) => {
12355                    (Some(prefix.as_str()), true)
12356                }
12357                Some(CommentFormat::BlockCommentWithEnd(BlockCommentConfig { prefix, .. })) => {
12358                    (Some(prefix.as_ref()), true)
12359                }
12360                Some(CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12361                    start: _,
12362                    end: _,
12363                    prefix,
12364                    tab_size,
12365                })) => {
12366                    indent_size.len += tab_size;
12367                    (Some(prefix.as_ref()), true)
12368                }
12369                None => (None, false),
12370            };
12371            let indent_prefix = indent_size.chars().collect::<String>();
12372            let line_prefix = format!("{indent_prefix}{}", line_prefix.unwrap_or(""));
12373
12374            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
12375                RewrapBehavior::InComments => inside_comment,
12376                RewrapBehavior::InSelections => !wrap_range.is_empty(),
12377                RewrapBehavior::Anywhere => true,
12378            };
12379
12380            let should_rewrap = options.override_language_settings
12381                || allow_rewrap_based_on_language
12382                || self.hard_wrap.is_some();
12383            if !should_rewrap {
12384                continue;
12385            }
12386
12387            if from_empty_selection {
12388                'expand_upwards: while start_row > 0 {
12389                    let prev_row = start_row - 1;
12390                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
12391                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
12392                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
12393                    {
12394                        start_row = prev_row;
12395                    } else {
12396                        break 'expand_upwards;
12397                    }
12398                }
12399
12400                'expand_downwards: while end_row < buffer.max_point().row {
12401                    let next_row = end_row + 1;
12402                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
12403                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
12404                        && !buffer.is_line_blank(MultiBufferRow(next_row))
12405                    {
12406                        end_row = next_row;
12407                    } else {
12408                        break 'expand_downwards;
12409                    }
12410                }
12411            }
12412
12413            let start = Point::new(start_row, 0);
12414            let start_offset = ToOffset::to_offset(&start, &buffer);
12415            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
12416            let selection_text = buffer.text_for_range(start..end).collect::<String>();
12417            let mut first_line_delimiter = None;
12418            let mut last_line_delimiter = None;
12419            let Some(lines_without_prefixes) = selection_text
12420                .lines()
12421                .enumerate()
12422                .map(|(ix, line)| {
12423                    let line_trimmed = line.trim_start();
12424                    if rewrap_prefix.is_some() && ix > 0 {
12425                        Ok(line_trimmed)
12426                    } else if let Some(
12427                        CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12428                            start,
12429                            prefix,
12430                            end,
12431                            tab_size,
12432                        })
12433                        | CommentFormat::BlockCommentWithEnd(BlockCommentConfig {
12434                            start,
12435                            prefix,
12436                            end,
12437                            tab_size,
12438                        }),
12439                    ) = &comment_prefix
12440                    {
12441                        let line_trimmed = line_trimmed
12442                            .strip_prefix(start.as_ref())
12443                            .map(|s| {
12444                                let mut indent_size = indent_size;
12445                                indent_size.len -= tab_size;
12446                                let indent_prefix: String = indent_size.chars().collect();
12447                                first_line_delimiter = Some((indent_prefix, start));
12448                                s.trim_start()
12449                            })
12450                            .unwrap_or(line_trimmed);
12451                        let line_trimmed = line_trimmed
12452                            .strip_suffix(end.as_ref())
12453                            .map(|s| {
12454                                last_line_delimiter = Some(end);
12455                                s.trim_end()
12456                            })
12457                            .unwrap_or(line_trimmed);
12458                        let line_trimmed = line_trimmed
12459                            .strip_prefix(prefix.as_ref())
12460                            .unwrap_or(line_trimmed);
12461                        Ok(line_trimmed)
12462                    } else if let Some(CommentFormat::BlockLine(prefix)) = &comment_prefix {
12463                        line_trimmed.strip_prefix(prefix).with_context(|| {
12464                            format!("line did not start with prefix {prefix:?}: {line:?}")
12465                        })
12466                    } else {
12467                        line_trimmed
12468                            .strip_prefix(&line_prefix.trim_start())
12469                            .with_context(|| {
12470                                format!("line did not start with prefix {line_prefix:?}: {line:?}")
12471                            })
12472                    }
12473                })
12474                .collect::<Result<Vec<_>, _>>()
12475                .log_err()
12476            else {
12477                continue;
12478            };
12479
12480            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
12481                buffer
12482                    .language_settings_at(Point::new(start_row, 0), cx)
12483                    .preferred_line_length as usize
12484            });
12485
12486            let subsequent_lines_prefix = if let Some(rewrap_prefix_str) = &rewrap_prefix {
12487                format!("{}{}", indent_prefix, " ".repeat(rewrap_prefix_str.len()))
12488            } else {
12489                line_prefix.clone()
12490            };
12491
12492            let wrapped_text = {
12493                let mut wrapped_text = wrap_with_prefix(
12494                    line_prefix,
12495                    subsequent_lines_prefix,
12496                    lines_without_prefixes.join("\n"),
12497                    wrap_column,
12498                    tab_size,
12499                    options.preserve_existing_whitespace,
12500                );
12501
12502                if let Some((indent, delimiter)) = first_line_delimiter {
12503                    wrapped_text = format!("{indent}{delimiter}\n{wrapped_text}");
12504                }
12505                if let Some(last_line) = last_line_delimiter {
12506                    wrapped_text = format!("{wrapped_text}\n{indent_prefix}{last_line}");
12507                }
12508
12509                wrapped_text
12510            };
12511
12512            // TODO: should always use char-based diff while still supporting cursor behavior that
12513            // matches vim.
12514            let mut diff_options = DiffOptions::default();
12515            if options.override_language_settings {
12516                diff_options.max_word_diff_len = 0;
12517                diff_options.max_word_diff_line_count = 0;
12518            } else {
12519                diff_options.max_word_diff_len = usize::MAX;
12520                diff_options.max_word_diff_line_count = usize::MAX;
12521            }
12522
12523            for (old_range, new_text) in
12524                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
12525            {
12526                let edit_start = buffer.anchor_after(start_offset + old_range.start);
12527                let edit_end = buffer.anchor_after(start_offset + old_range.end);
12528                edits.push((edit_start..edit_end, new_text));
12529            }
12530
12531            rewrapped_row_ranges.push(start_row..=end_row);
12532        }
12533
12534        self.buffer
12535            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12536    }
12537
12538    pub fn cut_common(
12539        &mut self,
12540        cut_no_selection_line: bool,
12541        window: &mut Window,
12542        cx: &mut Context<Self>,
12543    ) -> ClipboardItem {
12544        let mut text = String::new();
12545        let buffer = self.buffer.read(cx).snapshot(cx);
12546        let mut selections = self.selections.all::<Point>(&self.display_snapshot(cx));
12547        let mut clipboard_selections = Vec::with_capacity(selections.len());
12548        {
12549            let max_point = buffer.max_point();
12550            let mut is_first = true;
12551            for selection in &mut selections {
12552                let is_entire_line =
12553                    (selection.is_empty() && cut_no_selection_line) || self.selections.line_mode();
12554                if is_entire_line {
12555                    selection.start = Point::new(selection.start.row, 0);
12556                    if !selection.is_empty() && selection.end.column == 0 {
12557                        selection.end = cmp::min(max_point, selection.end);
12558                    } else {
12559                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
12560                    }
12561                    selection.goal = SelectionGoal::None;
12562                }
12563                if is_first {
12564                    is_first = false;
12565                } else {
12566                    text += "\n";
12567                }
12568                let mut len = 0;
12569                for chunk in buffer.text_for_range(selection.start..selection.end) {
12570                    text.push_str(chunk);
12571                    len += chunk.len();
12572                }
12573                clipboard_selections.push(ClipboardSelection {
12574                    len,
12575                    is_entire_line,
12576                    first_line_indent: buffer
12577                        .indent_size_for_line(MultiBufferRow(selection.start.row))
12578                        .len,
12579                });
12580            }
12581        }
12582
12583        self.transact(window, cx, |this, window, cx| {
12584            this.change_selections(Default::default(), window, cx, |s| {
12585                s.select(selections);
12586            });
12587            this.insert("", window, cx);
12588        });
12589        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
12590    }
12591
12592    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
12593        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12594        let item = self.cut_common(true, window, cx);
12595        cx.write_to_clipboard(item);
12596    }
12597
12598    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
12599        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12600        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12601            s.move_with(|snapshot, sel| {
12602                if sel.is_empty() {
12603                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()));
12604                }
12605                if sel.is_empty() {
12606                    sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
12607                }
12608            });
12609        });
12610        let item = self.cut_common(false, window, cx);
12611        cx.set_global(KillRing(item))
12612    }
12613
12614    pub fn kill_ring_yank(
12615        &mut self,
12616        _: &KillRingYank,
12617        window: &mut Window,
12618        cx: &mut Context<Self>,
12619    ) {
12620        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12621        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
12622            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
12623                (kill_ring.text().to_string(), kill_ring.metadata_json())
12624            } else {
12625                return;
12626            }
12627        } else {
12628            return;
12629        };
12630        self.do_paste(&text, metadata, false, window, cx);
12631    }
12632
12633    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
12634        self.do_copy(true, cx);
12635    }
12636
12637    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
12638        self.do_copy(false, cx);
12639    }
12640
12641    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
12642        let selections = self.selections.all::<Point>(&self.display_snapshot(cx));
12643        let buffer = self.buffer.read(cx).read(cx);
12644        let mut text = String::new();
12645
12646        let mut clipboard_selections = Vec::with_capacity(selections.len());
12647        {
12648            let max_point = buffer.max_point();
12649            let mut is_first = true;
12650            for selection in &selections {
12651                let mut start = selection.start;
12652                let mut end = selection.end;
12653                let is_entire_line = selection.is_empty() || self.selections.line_mode();
12654                let mut add_trailing_newline = false;
12655                if is_entire_line {
12656                    start = Point::new(start.row, 0);
12657                    let next_line_start = Point::new(end.row + 1, 0);
12658                    if next_line_start <= max_point {
12659                        end = next_line_start;
12660                    } else {
12661                        // We're on the last line without a trailing newline.
12662                        // Copy to the end of the line and add a newline afterwards.
12663                        end = Point::new(end.row, buffer.line_len(MultiBufferRow(end.row)));
12664                        add_trailing_newline = true;
12665                    }
12666                }
12667
12668                let mut trimmed_selections = Vec::new();
12669                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
12670                    let row = MultiBufferRow(start.row);
12671                    let first_indent = buffer.indent_size_for_line(row);
12672                    if first_indent.len == 0 || start.column > first_indent.len {
12673                        trimmed_selections.push(start..end);
12674                    } else {
12675                        trimmed_selections.push(
12676                            Point::new(row.0, first_indent.len)
12677                                ..Point::new(row.0, buffer.line_len(row)),
12678                        );
12679                        for row in start.row + 1..=end.row {
12680                            let mut line_len = buffer.line_len(MultiBufferRow(row));
12681                            if row == end.row {
12682                                line_len = end.column;
12683                            }
12684                            if line_len == 0 {
12685                                trimmed_selections
12686                                    .push(Point::new(row, 0)..Point::new(row, line_len));
12687                                continue;
12688                            }
12689                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
12690                            if row_indent_size.len >= first_indent.len {
12691                                trimmed_selections.push(
12692                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
12693                                );
12694                            } else {
12695                                trimmed_selections.clear();
12696                                trimmed_selections.push(start..end);
12697                                break;
12698                            }
12699                        }
12700                    }
12701                } else {
12702                    trimmed_selections.push(start..end);
12703                }
12704
12705                for trimmed_range in trimmed_selections {
12706                    if is_first {
12707                        is_first = false;
12708                    } else {
12709                        text += "\n";
12710                    }
12711                    let mut len = 0;
12712                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
12713                        text.push_str(chunk);
12714                        len += chunk.len();
12715                    }
12716                    if add_trailing_newline {
12717                        text.push('\n');
12718                        len += 1;
12719                    }
12720                    clipboard_selections.push(ClipboardSelection {
12721                        len,
12722                        is_entire_line,
12723                        first_line_indent: buffer
12724                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
12725                            .len,
12726                    });
12727                }
12728            }
12729        }
12730
12731        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
12732            text,
12733            clipboard_selections,
12734        ));
12735    }
12736
12737    pub fn do_paste(
12738        &mut self,
12739        text: &String,
12740        clipboard_selections: Option<Vec<ClipboardSelection>>,
12741        handle_entire_lines: bool,
12742        window: &mut Window,
12743        cx: &mut Context<Self>,
12744    ) {
12745        if self.read_only(cx) {
12746            return;
12747        }
12748
12749        let clipboard_text = Cow::Borrowed(text.as_str());
12750
12751        self.transact(window, cx, |this, window, cx| {
12752            let had_active_edit_prediction = this.has_active_edit_prediction();
12753            let display_map = this.display_snapshot(cx);
12754            let old_selections = this.selections.all::<usize>(&display_map);
12755            let cursor_offset = this.selections.last::<usize>(&display_map).head();
12756
12757            if let Some(mut clipboard_selections) = clipboard_selections {
12758                let all_selections_were_entire_line =
12759                    clipboard_selections.iter().all(|s| s.is_entire_line);
12760                let first_selection_indent_column =
12761                    clipboard_selections.first().map(|s| s.first_line_indent);
12762                if clipboard_selections.len() != old_selections.len() {
12763                    clipboard_selections.drain(..);
12764                }
12765                let mut auto_indent_on_paste = true;
12766
12767                this.buffer.update(cx, |buffer, cx| {
12768                    let snapshot = buffer.read(cx);
12769                    auto_indent_on_paste = snapshot
12770                        .language_settings_at(cursor_offset, cx)
12771                        .auto_indent_on_paste;
12772
12773                    let mut start_offset = 0;
12774                    let mut edits = Vec::new();
12775                    let mut original_indent_columns = Vec::new();
12776                    for (ix, selection) in old_selections.iter().enumerate() {
12777                        let to_insert;
12778                        let entire_line;
12779                        let original_indent_column;
12780                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
12781                            let end_offset = start_offset + clipboard_selection.len;
12782                            to_insert = &clipboard_text[start_offset..end_offset];
12783                            entire_line = clipboard_selection.is_entire_line;
12784                            start_offset = end_offset + 1;
12785                            original_indent_column = Some(clipboard_selection.first_line_indent);
12786                        } else {
12787                            to_insert = &*clipboard_text;
12788                            entire_line = all_selections_were_entire_line;
12789                            original_indent_column = first_selection_indent_column
12790                        }
12791
12792                        let (range, to_insert) =
12793                            if selection.is_empty() && handle_entire_lines && entire_line {
12794                                // If the corresponding selection was empty when this slice of the
12795                                // clipboard text was written, then the entire line containing the
12796                                // selection was copied. If this selection is also currently empty,
12797                                // then paste the line before the current line of the buffer.
12798                                let column = selection.start.to_point(&snapshot).column as usize;
12799                                let line_start = selection.start - column;
12800                                (line_start..line_start, Cow::Borrowed(to_insert))
12801                            } else {
12802                                let language = snapshot.language_at(selection.head());
12803                                let range = selection.range();
12804                                if let Some(language) = language
12805                                    && language.name() == "Markdown".into()
12806                                {
12807                                    edit_for_markdown_paste(
12808                                        &snapshot,
12809                                        range,
12810                                        to_insert,
12811                                        url::Url::parse(to_insert).ok(),
12812                                    )
12813                                } else {
12814                                    (range, Cow::Borrowed(to_insert))
12815                                }
12816                            };
12817
12818                        edits.push((range, to_insert));
12819                        original_indent_columns.push(original_indent_column);
12820                    }
12821                    drop(snapshot);
12822
12823                    buffer.edit(
12824                        edits,
12825                        if auto_indent_on_paste {
12826                            Some(AutoindentMode::Block {
12827                                original_indent_columns,
12828                            })
12829                        } else {
12830                            None
12831                        },
12832                        cx,
12833                    );
12834                });
12835
12836                let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
12837                this.change_selections(Default::default(), window, cx, |s| s.select(selections));
12838            } else {
12839                let url = url::Url::parse(&clipboard_text).ok();
12840
12841                let auto_indent_mode = if !clipboard_text.is_empty() {
12842                    Some(AutoindentMode::Block {
12843                        original_indent_columns: Vec::new(),
12844                    })
12845                } else {
12846                    None
12847                };
12848
12849                let selection_anchors = this.buffer.update(cx, |buffer, cx| {
12850                    let snapshot = buffer.snapshot(cx);
12851
12852                    let anchors = old_selections
12853                        .iter()
12854                        .map(|s| {
12855                            let anchor = snapshot.anchor_after(s.head());
12856                            s.map(|_| anchor)
12857                        })
12858                        .collect::<Vec<_>>();
12859
12860                    let mut edits = Vec::new();
12861
12862                    for selection in old_selections.iter() {
12863                        let language = snapshot.language_at(selection.head());
12864                        let range = selection.range();
12865
12866                        let (edit_range, edit_text) = if let Some(language) = language
12867                            && language.name() == "Markdown".into()
12868                        {
12869                            edit_for_markdown_paste(&snapshot, range, &clipboard_text, url.clone())
12870                        } else {
12871                            (range, clipboard_text.clone())
12872                        };
12873
12874                        edits.push((edit_range, edit_text));
12875                    }
12876
12877                    drop(snapshot);
12878                    buffer.edit(edits, auto_indent_mode, cx);
12879
12880                    anchors
12881                });
12882
12883                this.change_selections(Default::default(), window, cx, |s| {
12884                    s.select_anchors(selection_anchors);
12885                });
12886            }
12887
12888            //   🤔                 |    ..     | show_in_menu |
12889            // | ..                  |   true        true
12890            // | had_edit_prediction |   false       true
12891
12892            let trigger_in_words =
12893                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
12894
12895            this.trigger_completion_on_input(text, trigger_in_words, window, cx);
12896        });
12897    }
12898
12899    pub fn diff_clipboard_with_selection(
12900        &mut self,
12901        _: &DiffClipboardWithSelection,
12902        window: &mut Window,
12903        cx: &mut Context<Self>,
12904    ) {
12905        let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
12906
12907        if selections.is_empty() {
12908            log::warn!("There should always be at least one selection in Zed. This is a bug.");
12909            return;
12910        };
12911
12912        let clipboard_text = match cx.read_from_clipboard() {
12913            Some(item) => match item.entries().first() {
12914                Some(ClipboardEntry::String(text)) => Some(text.text().to_string()),
12915                _ => None,
12916            },
12917            None => None,
12918        };
12919
12920        let Some(clipboard_text) = clipboard_text else {
12921            log::warn!("Clipboard doesn't contain text.");
12922            return;
12923        };
12924
12925        window.dispatch_action(
12926            Box::new(DiffClipboardWithSelectionData {
12927                clipboard_text,
12928                editor: cx.entity(),
12929            }),
12930            cx,
12931        );
12932    }
12933
12934    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
12935        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12936        if let Some(item) = cx.read_from_clipboard() {
12937            let entries = item.entries();
12938
12939            match entries.first() {
12940                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
12941                // of all the pasted entries.
12942                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
12943                    .do_paste(
12944                        clipboard_string.text(),
12945                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
12946                        true,
12947                        window,
12948                        cx,
12949                    ),
12950                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
12951            }
12952        }
12953    }
12954
12955    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
12956        if self.read_only(cx) {
12957            return;
12958        }
12959
12960        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12961
12962        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
12963            if let Some((selections, _)) =
12964                self.selection_history.transaction(transaction_id).cloned()
12965            {
12966                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12967                    s.select_anchors(selections.to_vec());
12968                });
12969            } else {
12970                log::error!(
12971                    "No entry in selection_history found for undo. \
12972                     This may correspond to a bug where undo does not update the selection. \
12973                     If this is occurring, please add details to \
12974                     https://github.com/zed-industries/zed/issues/22692"
12975                );
12976            }
12977            self.request_autoscroll(Autoscroll::fit(), cx);
12978            self.unmark_text(window, cx);
12979            self.refresh_edit_prediction(true, false, window, cx);
12980            cx.emit(EditorEvent::Edited { transaction_id });
12981            cx.emit(EditorEvent::TransactionUndone { transaction_id });
12982        }
12983    }
12984
12985    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
12986        if self.read_only(cx) {
12987            return;
12988        }
12989
12990        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12991
12992        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
12993            if let Some((_, Some(selections))) =
12994                self.selection_history.transaction(transaction_id).cloned()
12995            {
12996                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12997                    s.select_anchors(selections.to_vec());
12998                });
12999            } else {
13000                log::error!(
13001                    "No entry in selection_history found for redo. \
13002                     This may correspond to a bug where undo does not update the selection. \
13003                     If this is occurring, please add details to \
13004                     https://github.com/zed-industries/zed/issues/22692"
13005                );
13006            }
13007            self.request_autoscroll(Autoscroll::fit(), cx);
13008            self.unmark_text(window, cx);
13009            self.refresh_edit_prediction(true, false, window, cx);
13010            cx.emit(EditorEvent::Edited { transaction_id });
13011        }
13012    }
13013
13014    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
13015        self.buffer
13016            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
13017    }
13018
13019    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
13020        self.buffer
13021            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
13022    }
13023
13024    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
13025        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13026        self.change_selections(Default::default(), window, cx, |s| {
13027            s.move_with(|map, selection| {
13028                let cursor = if selection.is_empty() {
13029                    movement::left(map, selection.start)
13030                } else {
13031                    selection.start
13032                };
13033                selection.collapse_to(cursor, SelectionGoal::None);
13034            });
13035        })
13036    }
13037
13038    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
13039        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13040        self.change_selections(Default::default(), window, cx, |s| {
13041            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
13042        })
13043    }
13044
13045    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
13046        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13047        self.change_selections(Default::default(), window, cx, |s| {
13048            s.move_with(|map, selection| {
13049                let cursor = if selection.is_empty() {
13050                    movement::right(map, selection.end)
13051                } else {
13052                    selection.end
13053                };
13054                selection.collapse_to(cursor, SelectionGoal::None)
13055            });
13056        })
13057    }
13058
13059    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
13060        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13061        self.change_selections(Default::default(), window, cx, |s| {
13062            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
13063        });
13064    }
13065
13066    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
13067        if self.take_rename(true, window, cx).is_some() {
13068            return;
13069        }
13070
13071        if self.mode.is_single_line() {
13072            cx.propagate();
13073            return;
13074        }
13075
13076        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13077
13078        let text_layout_details = &self.text_layout_details(window);
13079        let selection_count = self.selections.count();
13080        let first_selection = self.selections.first_anchor();
13081
13082        self.change_selections(Default::default(), window, cx, |s| {
13083            s.move_with(|map, selection| {
13084                if !selection.is_empty() {
13085                    selection.goal = SelectionGoal::None;
13086                }
13087                let (cursor, goal) = movement::up(
13088                    map,
13089                    selection.start,
13090                    selection.goal,
13091                    false,
13092                    text_layout_details,
13093                );
13094                selection.collapse_to(cursor, goal);
13095            });
13096        });
13097
13098        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
13099        {
13100            cx.propagate();
13101        }
13102    }
13103
13104    pub fn move_up_by_lines(
13105        &mut self,
13106        action: &MoveUpByLines,
13107        window: &mut Window,
13108        cx: &mut Context<Self>,
13109    ) {
13110        if self.take_rename(true, window, cx).is_some() {
13111            return;
13112        }
13113
13114        if self.mode.is_single_line() {
13115            cx.propagate();
13116            return;
13117        }
13118
13119        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13120
13121        let text_layout_details = &self.text_layout_details(window);
13122
13123        self.change_selections(Default::default(), window, cx, |s| {
13124            s.move_with(|map, selection| {
13125                if !selection.is_empty() {
13126                    selection.goal = SelectionGoal::None;
13127                }
13128                let (cursor, goal) = movement::up_by_rows(
13129                    map,
13130                    selection.start,
13131                    action.lines,
13132                    selection.goal,
13133                    false,
13134                    text_layout_details,
13135                );
13136                selection.collapse_to(cursor, goal);
13137            });
13138        })
13139    }
13140
13141    pub fn move_down_by_lines(
13142        &mut self,
13143        action: &MoveDownByLines,
13144        window: &mut Window,
13145        cx: &mut Context<Self>,
13146    ) {
13147        if self.take_rename(true, window, cx).is_some() {
13148            return;
13149        }
13150
13151        if self.mode.is_single_line() {
13152            cx.propagate();
13153            return;
13154        }
13155
13156        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13157
13158        let text_layout_details = &self.text_layout_details(window);
13159
13160        self.change_selections(Default::default(), window, cx, |s| {
13161            s.move_with(|map, selection| {
13162                if !selection.is_empty() {
13163                    selection.goal = SelectionGoal::None;
13164                }
13165                let (cursor, goal) = movement::down_by_rows(
13166                    map,
13167                    selection.start,
13168                    action.lines,
13169                    selection.goal,
13170                    false,
13171                    text_layout_details,
13172                );
13173                selection.collapse_to(cursor, goal);
13174            });
13175        })
13176    }
13177
13178    pub fn select_down_by_lines(
13179        &mut self,
13180        action: &SelectDownByLines,
13181        window: &mut Window,
13182        cx: &mut Context<Self>,
13183    ) {
13184        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13185        let text_layout_details = &self.text_layout_details(window);
13186        self.change_selections(Default::default(), window, cx, |s| {
13187            s.move_heads_with(|map, head, goal| {
13188                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
13189            })
13190        })
13191    }
13192
13193    pub fn select_up_by_lines(
13194        &mut self,
13195        action: &SelectUpByLines,
13196        window: &mut Window,
13197        cx: &mut Context<Self>,
13198    ) {
13199        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13200        let text_layout_details = &self.text_layout_details(window);
13201        self.change_selections(Default::default(), window, cx, |s| {
13202            s.move_heads_with(|map, head, goal| {
13203                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
13204            })
13205        })
13206    }
13207
13208    pub fn select_page_up(
13209        &mut self,
13210        _: &SelectPageUp,
13211        window: &mut Window,
13212        cx: &mut Context<Self>,
13213    ) {
13214        let Some(row_count) = self.visible_row_count() else {
13215            return;
13216        };
13217
13218        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13219
13220        let text_layout_details = &self.text_layout_details(window);
13221
13222        self.change_selections(Default::default(), window, cx, |s| {
13223            s.move_heads_with(|map, head, goal| {
13224                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
13225            })
13226        })
13227    }
13228
13229    pub fn move_page_up(
13230        &mut self,
13231        action: &MovePageUp,
13232        window: &mut Window,
13233        cx: &mut Context<Self>,
13234    ) {
13235        if self.take_rename(true, window, cx).is_some() {
13236            return;
13237        }
13238
13239        if self
13240            .context_menu
13241            .borrow_mut()
13242            .as_mut()
13243            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
13244            .unwrap_or(false)
13245        {
13246            return;
13247        }
13248
13249        if matches!(self.mode, EditorMode::SingleLine) {
13250            cx.propagate();
13251            return;
13252        }
13253
13254        let Some(row_count) = self.visible_row_count() else {
13255            return;
13256        };
13257
13258        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13259
13260        let effects = if action.center_cursor {
13261            SelectionEffects::scroll(Autoscroll::center())
13262        } else {
13263            SelectionEffects::default()
13264        };
13265
13266        let text_layout_details = &self.text_layout_details(window);
13267
13268        self.change_selections(effects, window, cx, |s| {
13269            s.move_with(|map, selection| {
13270                if !selection.is_empty() {
13271                    selection.goal = SelectionGoal::None;
13272                }
13273                let (cursor, goal) = movement::up_by_rows(
13274                    map,
13275                    selection.end,
13276                    row_count,
13277                    selection.goal,
13278                    false,
13279                    text_layout_details,
13280                );
13281                selection.collapse_to(cursor, goal);
13282            });
13283        });
13284    }
13285
13286    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
13287        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13288        let text_layout_details = &self.text_layout_details(window);
13289        self.change_selections(Default::default(), window, cx, |s| {
13290            s.move_heads_with(|map, head, goal| {
13291                movement::up(map, head, goal, false, text_layout_details)
13292            })
13293        })
13294    }
13295
13296    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
13297        self.take_rename(true, window, cx);
13298
13299        if self.mode.is_single_line() {
13300            cx.propagate();
13301            return;
13302        }
13303
13304        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13305
13306        let text_layout_details = &self.text_layout_details(window);
13307        let selection_count = self.selections.count();
13308        let first_selection = self.selections.first_anchor();
13309
13310        self.change_selections(Default::default(), window, cx, |s| {
13311            s.move_with(|map, selection| {
13312                if !selection.is_empty() {
13313                    selection.goal = SelectionGoal::None;
13314                }
13315                let (cursor, goal) = movement::down(
13316                    map,
13317                    selection.end,
13318                    selection.goal,
13319                    false,
13320                    text_layout_details,
13321                );
13322                selection.collapse_to(cursor, goal);
13323            });
13324        });
13325
13326        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
13327        {
13328            cx.propagate();
13329        }
13330    }
13331
13332    pub fn select_page_down(
13333        &mut self,
13334        _: &SelectPageDown,
13335        window: &mut Window,
13336        cx: &mut Context<Self>,
13337    ) {
13338        let Some(row_count) = self.visible_row_count() else {
13339            return;
13340        };
13341
13342        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13343
13344        let text_layout_details = &self.text_layout_details(window);
13345
13346        self.change_selections(Default::default(), window, cx, |s| {
13347            s.move_heads_with(|map, head, goal| {
13348                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
13349            })
13350        })
13351    }
13352
13353    pub fn move_page_down(
13354        &mut self,
13355        action: &MovePageDown,
13356        window: &mut Window,
13357        cx: &mut Context<Self>,
13358    ) {
13359        if self.take_rename(true, window, cx).is_some() {
13360            return;
13361        }
13362
13363        if self
13364            .context_menu
13365            .borrow_mut()
13366            .as_mut()
13367            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
13368            .unwrap_or(false)
13369        {
13370            return;
13371        }
13372
13373        if matches!(self.mode, EditorMode::SingleLine) {
13374            cx.propagate();
13375            return;
13376        }
13377
13378        let Some(row_count) = self.visible_row_count() else {
13379            return;
13380        };
13381
13382        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13383
13384        let effects = if action.center_cursor {
13385            SelectionEffects::scroll(Autoscroll::center())
13386        } else {
13387            SelectionEffects::default()
13388        };
13389
13390        let text_layout_details = &self.text_layout_details(window);
13391        self.change_selections(effects, window, cx, |s| {
13392            s.move_with(|map, selection| {
13393                if !selection.is_empty() {
13394                    selection.goal = SelectionGoal::None;
13395                }
13396                let (cursor, goal) = movement::down_by_rows(
13397                    map,
13398                    selection.end,
13399                    row_count,
13400                    selection.goal,
13401                    false,
13402                    text_layout_details,
13403                );
13404                selection.collapse_to(cursor, goal);
13405            });
13406        });
13407    }
13408
13409    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
13410        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13411        let text_layout_details = &self.text_layout_details(window);
13412        self.change_selections(Default::default(), window, cx, |s| {
13413            s.move_heads_with(|map, head, goal| {
13414                movement::down(map, head, goal, false, text_layout_details)
13415            })
13416        });
13417    }
13418
13419    pub fn context_menu_first(
13420        &mut self,
13421        _: &ContextMenuFirst,
13422        window: &mut Window,
13423        cx: &mut Context<Self>,
13424    ) {
13425        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13426            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
13427        }
13428    }
13429
13430    pub fn context_menu_prev(
13431        &mut self,
13432        _: &ContextMenuPrevious,
13433        window: &mut Window,
13434        cx: &mut Context<Self>,
13435    ) {
13436        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13437            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
13438        }
13439    }
13440
13441    pub fn context_menu_next(
13442        &mut self,
13443        _: &ContextMenuNext,
13444        window: &mut Window,
13445        cx: &mut Context<Self>,
13446    ) {
13447        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13448            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
13449        }
13450    }
13451
13452    pub fn context_menu_last(
13453        &mut self,
13454        _: &ContextMenuLast,
13455        window: &mut Window,
13456        cx: &mut Context<Self>,
13457    ) {
13458        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13459            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
13460        }
13461    }
13462
13463    pub fn signature_help_prev(
13464        &mut self,
13465        _: &SignatureHelpPrevious,
13466        _: &mut Window,
13467        cx: &mut Context<Self>,
13468    ) {
13469        if let Some(popover) = self.signature_help_state.popover_mut() {
13470            if popover.current_signature == 0 {
13471                popover.current_signature = popover.signatures.len() - 1;
13472            } else {
13473                popover.current_signature -= 1;
13474            }
13475            cx.notify();
13476        }
13477    }
13478
13479    pub fn signature_help_next(
13480        &mut self,
13481        _: &SignatureHelpNext,
13482        _: &mut Window,
13483        cx: &mut Context<Self>,
13484    ) {
13485        if let Some(popover) = self.signature_help_state.popover_mut() {
13486            if popover.current_signature + 1 == popover.signatures.len() {
13487                popover.current_signature = 0;
13488            } else {
13489                popover.current_signature += 1;
13490            }
13491            cx.notify();
13492        }
13493    }
13494
13495    pub fn move_to_previous_word_start(
13496        &mut self,
13497        _: &MoveToPreviousWordStart,
13498        window: &mut Window,
13499        cx: &mut Context<Self>,
13500    ) {
13501        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13502        self.change_selections(Default::default(), window, cx, |s| {
13503            s.move_cursors_with(|map, head, _| {
13504                (
13505                    movement::previous_word_start(map, head),
13506                    SelectionGoal::None,
13507                )
13508            });
13509        })
13510    }
13511
13512    pub fn move_to_previous_subword_start(
13513        &mut self,
13514        _: &MoveToPreviousSubwordStart,
13515        window: &mut Window,
13516        cx: &mut Context<Self>,
13517    ) {
13518        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13519        self.change_selections(Default::default(), window, cx, |s| {
13520            s.move_cursors_with(|map, head, _| {
13521                (
13522                    movement::previous_subword_start(map, head),
13523                    SelectionGoal::None,
13524                )
13525            });
13526        })
13527    }
13528
13529    pub fn select_to_previous_word_start(
13530        &mut self,
13531        _: &SelectToPreviousWordStart,
13532        window: &mut Window,
13533        cx: &mut Context<Self>,
13534    ) {
13535        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13536        self.change_selections(Default::default(), window, cx, |s| {
13537            s.move_heads_with(|map, head, _| {
13538                (
13539                    movement::previous_word_start(map, head),
13540                    SelectionGoal::None,
13541                )
13542            });
13543        })
13544    }
13545
13546    pub fn select_to_previous_subword_start(
13547        &mut self,
13548        _: &SelectToPreviousSubwordStart,
13549        window: &mut Window,
13550        cx: &mut Context<Self>,
13551    ) {
13552        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13553        self.change_selections(Default::default(), window, cx, |s| {
13554            s.move_heads_with(|map, head, _| {
13555                (
13556                    movement::previous_subword_start(map, head),
13557                    SelectionGoal::None,
13558                )
13559            });
13560        })
13561    }
13562
13563    pub fn delete_to_previous_word_start(
13564        &mut self,
13565        action: &DeleteToPreviousWordStart,
13566        window: &mut Window,
13567        cx: &mut Context<Self>,
13568    ) {
13569        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13570        self.transact(window, cx, |this, window, cx| {
13571            this.select_autoclose_pair(window, cx);
13572            this.change_selections(Default::default(), window, cx, |s| {
13573                s.move_with(|map, selection| {
13574                    if selection.is_empty() {
13575                        let mut cursor = if action.ignore_newlines {
13576                            movement::previous_word_start(map, selection.head())
13577                        } else {
13578                            movement::previous_word_start_or_newline(map, selection.head())
13579                        };
13580                        cursor = movement::adjust_greedy_deletion(
13581                            map,
13582                            selection.head(),
13583                            cursor,
13584                            action.ignore_brackets,
13585                        );
13586                        selection.set_head(cursor, SelectionGoal::None);
13587                    }
13588                });
13589            });
13590            this.insert("", window, cx);
13591        });
13592    }
13593
13594    pub fn delete_to_previous_subword_start(
13595        &mut self,
13596        _: &DeleteToPreviousSubwordStart,
13597        window: &mut Window,
13598        cx: &mut Context<Self>,
13599    ) {
13600        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13601        self.transact(window, cx, |this, window, cx| {
13602            this.select_autoclose_pair(window, cx);
13603            this.change_selections(Default::default(), window, cx, |s| {
13604                s.move_with(|map, selection| {
13605                    if selection.is_empty() {
13606                        let mut cursor = movement::previous_subword_start(map, selection.head());
13607                        cursor =
13608                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13609                        selection.set_head(cursor, SelectionGoal::None);
13610                    }
13611                });
13612            });
13613            this.insert("", window, cx);
13614        });
13615    }
13616
13617    pub fn move_to_next_word_end(
13618        &mut self,
13619        _: &MoveToNextWordEnd,
13620        window: &mut Window,
13621        cx: &mut Context<Self>,
13622    ) {
13623        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13624        self.change_selections(Default::default(), window, cx, |s| {
13625            s.move_cursors_with(|map, head, _| {
13626                (movement::next_word_end(map, head), SelectionGoal::None)
13627            });
13628        })
13629    }
13630
13631    pub fn move_to_next_subword_end(
13632        &mut self,
13633        _: &MoveToNextSubwordEnd,
13634        window: &mut Window,
13635        cx: &mut Context<Self>,
13636    ) {
13637        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13638        self.change_selections(Default::default(), window, cx, |s| {
13639            s.move_cursors_with(|map, head, _| {
13640                (movement::next_subword_end(map, head), SelectionGoal::None)
13641            });
13642        })
13643    }
13644
13645    pub fn select_to_next_word_end(
13646        &mut self,
13647        _: &SelectToNextWordEnd,
13648        window: &mut Window,
13649        cx: &mut Context<Self>,
13650    ) {
13651        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13652        self.change_selections(Default::default(), window, cx, |s| {
13653            s.move_heads_with(|map, head, _| {
13654                (movement::next_word_end(map, head), SelectionGoal::None)
13655            });
13656        })
13657    }
13658
13659    pub fn select_to_next_subword_end(
13660        &mut self,
13661        _: &SelectToNextSubwordEnd,
13662        window: &mut Window,
13663        cx: &mut Context<Self>,
13664    ) {
13665        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13666        self.change_selections(Default::default(), window, cx, |s| {
13667            s.move_heads_with(|map, head, _| {
13668                (movement::next_subword_end(map, head), SelectionGoal::None)
13669            });
13670        })
13671    }
13672
13673    pub fn delete_to_next_word_end(
13674        &mut self,
13675        action: &DeleteToNextWordEnd,
13676        window: &mut Window,
13677        cx: &mut Context<Self>,
13678    ) {
13679        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13680        self.transact(window, cx, |this, window, cx| {
13681            this.change_selections(Default::default(), window, cx, |s| {
13682                s.move_with(|map, selection| {
13683                    if selection.is_empty() {
13684                        let mut cursor = if action.ignore_newlines {
13685                            movement::next_word_end(map, selection.head())
13686                        } else {
13687                            movement::next_word_end_or_newline(map, selection.head())
13688                        };
13689                        cursor = movement::adjust_greedy_deletion(
13690                            map,
13691                            selection.head(),
13692                            cursor,
13693                            action.ignore_brackets,
13694                        );
13695                        selection.set_head(cursor, SelectionGoal::None);
13696                    }
13697                });
13698            });
13699            this.insert("", window, cx);
13700        });
13701    }
13702
13703    pub fn delete_to_next_subword_end(
13704        &mut self,
13705        _: &DeleteToNextSubwordEnd,
13706        window: &mut Window,
13707        cx: &mut Context<Self>,
13708    ) {
13709        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13710        self.transact(window, cx, |this, window, cx| {
13711            this.change_selections(Default::default(), window, cx, |s| {
13712                s.move_with(|map, selection| {
13713                    if selection.is_empty() {
13714                        let mut cursor = movement::next_subword_end(map, selection.head());
13715                        cursor =
13716                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13717                        selection.set_head(cursor, SelectionGoal::None);
13718                    }
13719                });
13720            });
13721            this.insert("", window, cx);
13722        });
13723    }
13724
13725    pub fn move_to_beginning_of_line(
13726        &mut self,
13727        action: &MoveToBeginningOfLine,
13728        window: &mut Window,
13729        cx: &mut Context<Self>,
13730    ) {
13731        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13732        self.change_selections(Default::default(), window, cx, |s| {
13733            s.move_cursors_with(|map, head, _| {
13734                (
13735                    movement::indented_line_beginning(
13736                        map,
13737                        head,
13738                        action.stop_at_soft_wraps,
13739                        action.stop_at_indent,
13740                    ),
13741                    SelectionGoal::None,
13742                )
13743            });
13744        })
13745    }
13746
13747    pub fn select_to_beginning_of_line(
13748        &mut self,
13749        action: &SelectToBeginningOfLine,
13750        window: &mut Window,
13751        cx: &mut Context<Self>,
13752    ) {
13753        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13754        self.change_selections(Default::default(), window, cx, |s| {
13755            s.move_heads_with(|map, head, _| {
13756                (
13757                    movement::indented_line_beginning(
13758                        map,
13759                        head,
13760                        action.stop_at_soft_wraps,
13761                        action.stop_at_indent,
13762                    ),
13763                    SelectionGoal::None,
13764                )
13765            });
13766        });
13767    }
13768
13769    pub fn delete_to_beginning_of_line(
13770        &mut self,
13771        action: &DeleteToBeginningOfLine,
13772        window: &mut Window,
13773        cx: &mut Context<Self>,
13774    ) {
13775        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13776        self.transact(window, cx, |this, window, cx| {
13777            this.change_selections(Default::default(), window, cx, |s| {
13778                s.move_with(|_, selection| {
13779                    selection.reversed = true;
13780                });
13781            });
13782
13783            this.select_to_beginning_of_line(
13784                &SelectToBeginningOfLine {
13785                    stop_at_soft_wraps: false,
13786                    stop_at_indent: action.stop_at_indent,
13787                },
13788                window,
13789                cx,
13790            );
13791            this.backspace(&Backspace, window, cx);
13792        });
13793    }
13794
13795    pub fn move_to_end_of_line(
13796        &mut self,
13797        action: &MoveToEndOfLine,
13798        window: &mut Window,
13799        cx: &mut Context<Self>,
13800    ) {
13801        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13802        self.change_selections(Default::default(), window, cx, |s| {
13803            s.move_cursors_with(|map, head, _| {
13804                (
13805                    movement::line_end(map, head, action.stop_at_soft_wraps),
13806                    SelectionGoal::None,
13807                )
13808            });
13809        })
13810    }
13811
13812    pub fn select_to_end_of_line(
13813        &mut self,
13814        action: &SelectToEndOfLine,
13815        window: &mut Window,
13816        cx: &mut Context<Self>,
13817    ) {
13818        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13819        self.change_selections(Default::default(), window, cx, |s| {
13820            s.move_heads_with(|map, head, _| {
13821                (
13822                    movement::line_end(map, head, action.stop_at_soft_wraps),
13823                    SelectionGoal::None,
13824                )
13825            });
13826        })
13827    }
13828
13829    pub fn delete_to_end_of_line(
13830        &mut self,
13831        _: &DeleteToEndOfLine,
13832        window: &mut Window,
13833        cx: &mut Context<Self>,
13834    ) {
13835        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13836        self.transact(window, cx, |this, window, cx| {
13837            this.select_to_end_of_line(
13838                &SelectToEndOfLine {
13839                    stop_at_soft_wraps: false,
13840                },
13841                window,
13842                cx,
13843            );
13844            this.delete(&Delete, window, cx);
13845        });
13846    }
13847
13848    pub fn cut_to_end_of_line(
13849        &mut self,
13850        action: &CutToEndOfLine,
13851        window: &mut Window,
13852        cx: &mut Context<Self>,
13853    ) {
13854        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13855        self.transact(window, cx, |this, window, cx| {
13856            this.select_to_end_of_line(
13857                &SelectToEndOfLine {
13858                    stop_at_soft_wraps: false,
13859                },
13860                window,
13861                cx,
13862            );
13863            if !action.stop_at_newlines {
13864                this.change_selections(Default::default(), window, cx, |s| {
13865                    s.move_with(|_, sel| {
13866                        if sel.is_empty() {
13867                            sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
13868                        }
13869                    });
13870                });
13871            }
13872            this.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13873            let item = this.cut_common(false, window, cx);
13874            cx.write_to_clipboard(item);
13875        });
13876    }
13877
13878    pub fn move_to_start_of_paragraph(
13879        &mut self,
13880        _: &MoveToStartOfParagraph,
13881        window: &mut Window,
13882        cx: &mut Context<Self>,
13883    ) {
13884        if matches!(self.mode, EditorMode::SingleLine) {
13885            cx.propagate();
13886            return;
13887        }
13888        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13889        self.change_selections(Default::default(), window, cx, |s| {
13890            s.move_with(|map, selection| {
13891                selection.collapse_to(
13892                    movement::start_of_paragraph(map, selection.head(), 1),
13893                    SelectionGoal::None,
13894                )
13895            });
13896        })
13897    }
13898
13899    pub fn move_to_end_of_paragraph(
13900        &mut self,
13901        _: &MoveToEndOfParagraph,
13902        window: &mut Window,
13903        cx: &mut Context<Self>,
13904    ) {
13905        if matches!(self.mode, EditorMode::SingleLine) {
13906            cx.propagate();
13907            return;
13908        }
13909        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13910        self.change_selections(Default::default(), window, cx, |s| {
13911            s.move_with(|map, selection| {
13912                selection.collapse_to(
13913                    movement::end_of_paragraph(map, selection.head(), 1),
13914                    SelectionGoal::None,
13915                )
13916            });
13917        })
13918    }
13919
13920    pub fn select_to_start_of_paragraph(
13921        &mut self,
13922        _: &SelectToStartOfParagraph,
13923        window: &mut Window,
13924        cx: &mut Context<Self>,
13925    ) {
13926        if matches!(self.mode, EditorMode::SingleLine) {
13927            cx.propagate();
13928            return;
13929        }
13930        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13931        self.change_selections(Default::default(), window, cx, |s| {
13932            s.move_heads_with(|map, head, _| {
13933                (
13934                    movement::start_of_paragraph(map, head, 1),
13935                    SelectionGoal::None,
13936                )
13937            });
13938        })
13939    }
13940
13941    pub fn select_to_end_of_paragraph(
13942        &mut self,
13943        _: &SelectToEndOfParagraph,
13944        window: &mut Window,
13945        cx: &mut Context<Self>,
13946    ) {
13947        if matches!(self.mode, EditorMode::SingleLine) {
13948            cx.propagate();
13949            return;
13950        }
13951        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13952        self.change_selections(Default::default(), window, cx, |s| {
13953            s.move_heads_with(|map, head, _| {
13954                (
13955                    movement::end_of_paragraph(map, head, 1),
13956                    SelectionGoal::None,
13957                )
13958            });
13959        })
13960    }
13961
13962    pub fn move_to_start_of_excerpt(
13963        &mut self,
13964        _: &MoveToStartOfExcerpt,
13965        window: &mut Window,
13966        cx: &mut Context<Self>,
13967    ) {
13968        if matches!(self.mode, EditorMode::SingleLine) {
13969            cx.propagate();
13970            return;
13971        }
13972        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13973        self.change_selections(Default::default(), window, cx, |s| {
13974            s.move_with(|map, selection| {
13975                selection.collapse_to(
13976                    movement::start_of_excerpt(
13977                        map,
13978                        selection.head(),
13979                        workspace::searchable::Direction::Prev,
13980                    ),
13981                    SelectionGoal::None,
13982                )
13983            });
13984        })
13985    }
13986
13987    pub fn move_to_start_of_next_excerpt(
13988        &mut self,
13989        _: &MoveToStartOfNextExcerpt,
13990        window: &mut Window,
13991        cx: &mut Context<Self>,
13992    ) {
13993        if matches!(self.mode, EditorMode::SingleLine) {
13994            cx.propagate();
13995            return;
13996        }
13997
13998        self.change_selections(Default::default(), window, cx, |s| {
13999            s.move_with(|map, selection| {
14000                selection.collapse_to(
14001                    movement::start_of_excerpt(
14002                        map,
14003                        selection.head(),
14004                        workspace::searchable::Direction::Next,
14005                    ),
14006                    SelectionGoal::None,
14007                )
14008            });
14009        })
14010    }
14011
14012    pub fn move_to_end_of_excerpt(
14013        &mut self,
14014        _: &MoveToEndOfExcerpt,
14015        window: &mut Window,
14016        cx: &mut Context<Self>,
14017    ) {
14018        if matches!(self.mode, EditorMode::SingleLine) {
14019            cx.propagate();
14020            return;
14021        }
14022        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14023        self.change_selections(Default::default(), window, cx, |s| {
14024            s.move_with(|map, selection| {
14025                selection.collapse_to(
14026                    movement::end_of_excerpt(
14027                        map,
14028                        selection.head(),
14029                        workspace::searchable::Direction::Next,
14030                    ),
14031                    SelectionGoal::None,
14032                )
14033            });
14034        })
14035    }
14036
14037    pub fn move_to_end_of_previous_excerpt(
14038        &mut self,
14039        _: &MoveToEndOfPreviousExcerpt,
14040        window: &mut Window,
14041        cx: &mut Context<Self>,
14042    ) {
14043        if matches!(self.mode, EditorMode::SingleLine) {
14044            cx.propagate();
14045            return;
14046        }
14047        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14048        self.change_selections(Default::default(), window, cx, |s| {
14049            s.move_with(|map, selection| {
14050                selection.collapse_to(
14051                    movement::end_of_excerpt(
14052                        map,
14053                        selection.head(),
14054                        workspace::searchable::Direction::Prev,
14055                    ),
14056                    SelectionGoal::None,
14057                )
14058            });
14059        })
14060    }
14061
14062    pub fn select_to_start_of_excerpt(
14063        &mut self,
14064        _: &SelectToStartOfExcerpt,
14065        window: &mut Window,
14066        cx: &mut Context<Self>,
14067    ) {
14068        if matches!(self.mode, EditorMode::SingleLine) {
14069            cx.propagate();
14070            return;
14071        }
14072        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14073        self.change_selections(Default::default(), window, cx, |s| {
14074            s.move_heads_with(|map, head, _| {
14075                (
14076                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
14077                    SelectionGoal::None,
14078                )
14079            });
14080        })
14081    }
14082
14083    pub fn select_to_start_of_next_excerpt(
14084        &mut self,
14085        _: &SelectToStartOfNextExcerpt,
14086        window: &mut Window,
14087        cx: &mut Context<Self>,
14088    ) {
14089        if matches!(self.mode, EditorMode::SingleLine) {
14090            cx.propagate();
14091            return;
14092        }
14093        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14094        self.change_selections(Default::default(), window, cx, |s| {
14095            s.move_heads_with(|map, head, _| {
14096                (
14097                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
14098                    SelectionGoal::None,
14099                )
14100            });
14101        })
14102    }
14103
14104    pub fn select_to_end_of_excerpt(
14105        &mut self,
14106        _: &SelectToEndOfExcerpt,
14107        window: &mut Window,
14108        cx: &mut Context<Self>,
14109    ) {
14110        if matches!(self.mode, EditorMode::SingleLine) {
14111            cx.propagate();
14112            return;
14113        }
14114        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14115        self.change_selections(Default::default(), window, cx, |s| {
14116            s.move_heads_with(|map, head, _| {
14117                (
14118                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
14119                    SelectionGoal::None,
14120                )
14121            });
14122        })
14123    }
14124
14125    pub fn select_to_end_of_previous_excerpt(
14126        &mut self,
14127        _: &SelectToEndOfPreviousExcerpt,
14128        window: &mut Window,
14129        cx: &mut Context<Self>,
14130    ) {
14131        if matches!(self.mode, EditorMode::SingleLine) {
14132            cx.propagate();
14133            return;
14134        }
14135        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14136        self.change_selections(Default::default(), window, cx, |s| {
14137            s.move_heads_with(|map, head, _| {
14138                (
14139                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
14140                    SelectionGoal::None,
14141                )
14142            });
14143        })
14144    }
14145
14146    pub fn move_to_beginning(
14147        &mut self,
14148        _: &MoveToBeginning,
14149        window: &mut Window,
14150        cx: &mut Context<Self>,
14151    ) {
14152        if matches!(self.mode, EditorMode::SingleLine) {
14153            cx.propagate();
14154            return;
14155        }
14156        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14157        self.change_selections(Default::default(), window, cx, |s| {
14158            s.select_ranges(vec![0..0]);
14159        });
14160    }
14161
14162    pub fn select_to_beginning(
14163        &mut self,
14164        _: &SelectToBeginning,
14165        window: &mut Window,
14166        cx: &mut Context<Self>,
14167    ) {
14168        let mut selection = self.selections.last::<Point>(&self.display_snapshot(cx));
14169        selection.set_head(Point::zero(), SelectionGoal::None);
14170        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14171        self.change_selections(Default::default(), window, cx, |s| {
14172            s.select(vec![selection]);
14173        });
14174    }
14175
14176    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
14177        if matches!(self.mode, EditorMode::SingleLine) {
14178            cx.propagate();
14179            return;
14180        }
14181        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14182        let cursor = self.buffer.read(cx).read(cx).len();
14183        self.change_selections(Default::default(), window, cx, |s| {
14184            s.select_ranges(vec![cursor..cursor])
14185        });
14186    }
14187
14188    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
14189        self.nav_history = nav_history;
14190    }
14191
14192    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
14193        self.nav_history.as_ref()
14194    }
14195
14196    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
14197        self.push_to_nav_history(
14198            self.selections.newest_anchor().head(),
14199            None,
14200            false,
14201            true,
14202            cx,
14203        );
14204    }
14205
14206    fn push_to_nav_history(
14207        &mut self,
14208        cursor_anchor: Anchor,
14209        new_position: Option<Point>,
14210        is_deactivate: bool,
14211        always: bool,
14212        cx: &mut Context<Self>,
14213    ) {
14214        if let Some(nav_history) = self.nav_history.as_mut() {
14215            let buffer = self.buffer.read(cx).read(cx);
14216            let cursor_position = cursor_anchor.to_point(&buffer);
14217            let scroll_state = self.scroll_manager.anchor();
14218            let scroll_top_row = scroll_state.top_row(&buffer);
14219            drop(buffer);
14220
14221            if let Some(new_position) = new_position {
14222                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
14223                if row_delta == 0 || (row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA && !always) {
14224                    return;
14225                }
14226            }
14227
14228            nav_history.push(
14229                Some(NavigationData {
14230                    cursor_anchor,
14231                    cursor_position,
14232                    scroll_anchor: scroll_state,
14233                    scroll_top_row,
14234                }),
14235                cx,
14236            );
14237            cx.emit(EditorEvent::PushedToNavHistory {
14238                anchor: cursor_anchor,
14239                is_deactivate,
14240            })
14241        }
14242    }
14243
14244    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
14245        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14246        let buffer = self.buffer.read(cx).snapshot(cx);
14247        let mut selection = self.selections.first::<usize>(&self.display_snapshot(cx));
14248        selection.set_head(buffer.len(), SelectionGoal::None);
14249        self.change_selections(Default::default(), window, cx, |s| {
14250            s.select(vec![selection]);
14251        });
14252    }
14253
14254    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
14255        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14256        let end = self.buffer.read(cx).read(cx).len();
14257        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14258            s.select_ranges(vec![0..end]);
14259        });
14260    }
14261
14262    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
14263        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14264        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14265        let mut selections = self.selections.all::<Point>(&display_map);
14266        let max_point = display_map.buffer_snapshot().max_point();
14267        for selection in &mut selections {
14268            let rows = selection.spanned_rows(true, &display_map);
14269            selection.start = Point::new(rows.start.0, 0);
14270            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
14271            selection.reversed = false;
14272        }
14273        self.change_selections(Default::default(), window, cx, |s| {
14274            s.select(selections);
14275        });
14276    }
14277
14278    pub fn split_selection_into_lines(
14279        &mut self,
14280        action: &SplitSelectionIntoLines,
14281        window: &mut Window,
14282        cx: &mut Context<Self>,
14283    ) {
14284        let selections = self
14285            .selections
14286            .all::<Point>(&self.display_snapshot(cx))
14287            .into_iter()
14288            .map(|selection| selection.start..selection.end)
14289            .collect::<Vec<_>>();
14290        self.unfold_ranges(&selections, true, true, cx);
14291
14292        let mut new_selection_ranges = Vec::new();
14293        {
14294            let buffer = self.buffer.read(cx).read(cx);
14295            for selection in selections {
14296                for row in selection.start.row..selection.end.row {
14297                    let line_start = Point::new(row, 0);
14298                    let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
14299
14300                    if action.keep_selections {
14301                        // Keep the selection range for each line
14302                        let selection_start = if row == selection.start.row {
14303                            selection.start
14304                        } else {
14305                            line_start
14306                        };
14307                        new_selection_ranges.push(selection_start..line_end);
14308                    } else {
14309                        // Collapse to cursor at end of line
14310                        new_selection_ranges.push(line_end..line_end);
14311                    }
14312                }
14313
14314                let is_multiline_selection = selection.start.row != selection.end.row;
14315                // Don't insert last one if it's a multi-line selection ending at the start of a line,
14316                // so this action feels more ergonomic when paired with other selection operations
14317                let should_skip_last = is_multiline_selection && selection.end.column == 0;
14318                if !should_skip_last {
14319                    if action.keep_selections {
14320                        if is_multiline_selection {
14321                            let line_start = Point::new(selection.end.row, 0);
14322                            new_selection_ranges.push(line_start..selection.end);
14323                        } else {
14324                            new_selection_ranges.push(selection.start..selection.end);
14325                        }
14326                    } else {
14327                        new_selection_ranges.push(selection.end..selection.end);
14328                    }
14329                }
14330            }
14331        }
14332        self.change_selections(Default::default(), window, cx, |s| {
14333            s.select_ranges(new_selection_ranges);
14334        });
14335    }
14336
14337    pub fn add_selection_above(
14338        &mut self,
14339        action: &AddSelectionAbove,
14340        window: &mut Window,
14341        cx: &mut Context<Self>,
14342    ) {
14343        self.add_selection(true, action.skip_soft_wrap, window, cx);
14344    }
14345
14346    pub fn add_selection_below(
14347        &mut self,
14348        action: &AddSelectionBelow,
14349        window: &mut Window,
14350        cx: &mut Context<Self>,
14351    ) {
14352        self.add_selection(false, action.skip_soft_wrap, window, cx);
14353    }
14354
14355    fn add_selection(
14356        &mut self,
14357        above: bool,
14358        skip_soft_wrap: bool,
14359        window: &mut Window,
14360        cx: &mut Context<Self>,
14361    ) {
14362        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14363
14364        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14365        let all_selections = self.selections.all::<Point>(&display_map);
14366        let text_layout_details = self.text_layout_details(window);
14367
14368        let (mut columnar_selections, new_selections_to_columnarize) = {
14369            if let Some(state) = self.add_selections_state.as_ref() {
14370                let columnar_selection_ids: HashSet<_> = state
14371                    .groups
14372                    .iter()
14373                    .flat_map(|group| group.stack.iter())
14374                    .copied()
14375                    .collect();
14376
14377                all_selections
14378                    .into_iter()
14379                    .partition(|s| columnar_selection_ids.contains(&s.id))
14380            } else {
14381                (Vec::new(), all_selections)
14382            }
14383        };
14384
14385        let mut state = self
14386            .add_selections_state
14387            .take()
14388            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
14389
14390        for selection in new_selections_to_columnarize {
14391            let range = selection.display_range(&display_map).sorted();
14392            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
14393            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
14394            let positions = start_x.min(end_x)..start_x.max(end_x);
14395            let mut stack = Vec::new();
14396            for row in range.start.row().0..=range.end.row().0 {
14397                if let Some(selection) = self.selections.build_columnar_selection(
14398                    &display_map,
14399                    DisplayRow(row),
14400                    &positions,
14401                    selection.reversed,
14402                    &text_layout_details,
14403                ) {
14404                    stack.push(selection.id);
14405                    columnar_selections.push(selection);
14406                }
14407            }
14408            if !stack.is_empty() {
14409                if above {
14410                    stack.reverse();
14411                }
14412                state.groups.push(AddSelectionsGroup { above, stack });
14413            }
14414        }
14415
14416        let mut final_selections = Vec::new();
14417        let end_row = if above {
14418            DisplayRow(0)
14419        } else {
14420            display_map.max_point().row()
14421        };
14422
14423        let mut last_added_item_per_group = HashMap::default();
14424        for group in state.groups.iter_mut() {
14425            if let Some(last_id) = group.stack.last() {
14426                last_added_item_per_group.insert(*last_id, group);
14427            }
14428        }
14429
14430        for selection in columnar_selections {
14431            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
14432                if above == group.above {
14433                    let range = selection.display_range(&display_map).sorted();
14434                    debug_assert_eq!(range.start.row(), range.end.row());
14435                    let mut row = range.start.row();
14436                    let positions =
14437                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
14438                            Pixels::from(start)..Pixels::from(end)
14439                        } else {
14440                            let start_x =
14441                                display_map.x_for_display_point(range.start, &text_layout_details);
14442                            let end_x =
14443                                display_map.x_for_display_point(range.end, &text_layout_details);
14444                            start_x.min(end_x)..start_x.max(end_x)
14445                        };
14446
14447                    let mut maybe_new_selection = None;
14448                    let direction = if above { -1 } else { 1 };
14449
14450                    while row != end_row {
14451                        if skip_soft_wrap {
14452                            row = display_map
14453                                .start_of_relative_buffer_row(DisplayPoint::new(row, 0), direction)
14454                                .row();
14455                        } else if above {
14456                            row.0 -= 1;
14457                        } else {
14458                            row.0 += 1;
14459                        }
14460
14461                        if let Some(new_selection) = self.selections.build_columnar_selection(
14462                            &display_map,
14463                            row,
14464                            &positions,
14465                            selection.reversed,
14466                            &text_layout_details,
14467                        ) {
14468                            maybe_new_selection = Some(new_selection);
14469                            break;
14470                        }
14471                    }
14472
14473                    if let Some(new_selection) = maybe_new_selection {
14474                        group.stack.push(new_selection.id);
14475                        if above {
14476                            final_selections.push(new_selection);
14477                            final_selections.push(selection);
14478                        } else {
14479                            final_selections.push(selection);
14480                            final_selections.push(new_selection);
14481                        }
14482                    } else {
14483                        final_selections.push(selection);
14484                    }
14485                } else {
14486                    group.stack.pop();
14487                }
14488            } else {
14489                final_selections.push(selection);
14490            }
14491        }
14492
14493        self.change_selections(Default::default(), window, cx, |s| {
14494            s.select(final_selections);
14495        });
14496
14497        let final_selection_ids: HashSet<_> = self
14498            .selections
14499            .all::<Point>(&display_map)
14500            .iter()
14501            .map(|s| s.id)
14502            .collect();
14503        state.groups.retain_mut(|group| {
14504            // selections might get merged above so we remove invalid items from stacks
14505            group.stack.retain(|id| final_selection_ids.contains(id));
14506
14507            // single selection in stack can be treated as initial state
14508            group.stack.len() > 1
14509        });
14510
14511        if !state.groups.is_empty() {
14512            self.add_selections_state = Some(state);
14513        }
14514    }
14515
14516    fn select_match_ranges(
14517        &mut self,
14518        range: Range<usize>,
14519        reversed: bool,
14520        replace_newest: bool,
14521        auto_scroll: Option<Autoscroll>,
14522        window: &mut Window,
14523        cx: &mut Context<Editor>,
14524    ) {
14525        self.unfold_ranges(
14526            std::slice::from_ref(&range),
14527            false,
14528            auto_scroll.is_some(),
14529            cx,
14530        );
14531        let effects = if let Some(scroll) = auto_scroll {
14532            SelectionEffects::scroll(scroll)
14533        } else {
14534            SelectionEffects::no_scroll()
14535        };
14536        self.change_selections(effects, window, cx, |s| {
14537            if replace_newest {
14538                s.delete(s.newest_anchor().id);
14539            }
14540            if reversed {
14541                s.insert_range(range.end..range.start);
14542            } else {
14543                s.insert_range(range);
14544            }
14545        });
14546    }
14547
14548    pub fn select_next_match_internal(
14549        &mut self,
14550        display_map: &DisplaySnapshot,
14551        replace_newest: bool,
14552        autoscroll: Option<Autoscroll>,
14553        window: &mut Window,
14554        cx: &mut Context<Self>,
14555    ) -> Result<()> {
14556        let buffer = display_map.buffer_snapshot();
14557        let mut selections = self.selections.all::<usize>(&display_map);
14558        if let Some(mut select_next_state) = self.select_next_state.take() {
14559            let query = &select_next_state.query;
14560            if !select_next_state.done {
14561                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14562                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14563                let mut next_selected_range = None;
14564
14565                let bytes_after_last_selection =
14566                    buffer.bytes_in_range(last_selection.end..buffer.len());
14567                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
14568                let query_matches = query
14569                    .stream_find_iter(bytes_after_last_selection)
14570                    .map(|result| (last_selection.end, result))
14571                    .chain(
14572                        query
14573                            .stream_find_iter(bytes_before_first_selection)
14574                            .map(|result| (0, result)),
14575                    );
14576
14577                for (start_offset, query_match) in query_matches {
14578                    let query_match = query_match.unwrap(); // can only fail due to I/O
14579                    let offset_range =
14580                        start_offset + query_match.start()..start_offset + query_match.end();
14581
14582                    if !select_next_state.wordwise
14583                        || (!buffer.is_inside_word(offset_range.start, None)
14584                            && !buffer.is_inside_word(offset_range.end, None))
14585                    {
14586                        let idx = selections
14587                            .partition_point(|selection| selection.end <= offset_range.start);
14588                        let overlaps = selections
14589                            .get(idx)
14590                            .map_or(false, |selection| selection.start < offset_range.end);
14591
14592                        if !overlaps {
14593                            next_selected_range = Some(offset_range);
14594                            break;
14595                        }
14596                    }
14597                }
14598
14599                if let Some(next_selected_range) = next_selected_range {
14600                    self.select_match_ranges(
14601                        next_selected_range,
14602                        last_selection.reversed,
14603                        replace_newest,
14604                        autoscroll,
14605                        window,
14606                        cx,
14607                    );
14608                } else {
14609                    select_next_state.done = true;
14610                }
14611            }
14612
14613            self.select_next_state = Some(select_next_state);
14614        } else {
14615            let mut only_carets = true;
14616            let mut same_text_selected = true;
14617            let mut selected_text = None;
14618
14619            let mut selections_iter = selections.iter().peekable();
14620            while let Some(selection) = selections_iter.next() {
14621                if selection.start != selection.end {
14622                    only_carets = false;
14623                }
14624
14625                if same_text_selected {
14626                    if selected_text.is_none() {
14627                        selected_text =
14628                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14629                    }
14630
14631                    if let Some(next_selection) = selections_iter.peek() {
14632                        if next_selection.range().len() == selection.range().len() {
14633                            let next_selected_text = buffer
14634                                .text_for_range(next_selection.range())
14635                                .collect::<String>();
14636                            if Some(next_selected_text) != selected_text {
14637                                same_text_selected = false;
14638                                selected_text = None;
14639                            }
14640                        } else {
14641                            same_text_selected = false;
14642                            selected_text = None;
14643                        }
14644                    }
14645                }
14646            }
14647
14648            if only_carets {
14649                for selection in &mut selections {
14650                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
14651                    selection.start = word_range.start;
14652                    selection.end = word_range.end;
14653                    selection.goal = SelectionGoal::None;
14654                    selection.reversed = false;
14655                    self.select_match_ranges(
14656                        selection.start..selection.end,
14657                        selection.reversed,
14658                        replace_newest,
14659                        autoscroll,
14660                        window,
14661                        cx,
14662                    );
14663                }
14664
14665                if selections.len() == 1 {
14666                    let selection = selections
14667                        .last()
14668                        .expect("ensured that there's only one selection");
14669                    let query = buffer
14670                        .text_for_range(selection.start..selection.end)
14671                        .collect::<String>();
14672                    let is_empty = query.is_empty();
14673                    let select_state = SelectNextState {
14674                        query: self.build_query(&[query], cx)?,
14675                        wordwise: true,
14676                        done: is_empty,
14677                    };
14678                    self.select_next_state = Some(select_state);
14679                } else {
14680                    self.select_next_state = None;
14681                }
14682            } else if let Some(selected_text) = selected_text {
14683                self.select_next_state = Some(SelectNextState {
14684                    query: self.build_query(&[selected_text], cx)?,
14685                    wordwise: false,
14686                    done: false,
14687                });
14688                self.select_next_match_internal(
14689                    display_map,
14690                    replace_newest,
14691                    autoscroll,
14692                    window,
14693                    cx,
14694                )?;
14695            }
14696        }
14697        Ok(())
14698    }
14699
14700    pub fn select_all_matches(
14701        &mut self,
14702        _action: &SelectAllMatches,
14703        window: &mut Window,
14704        cx: &mut Context<Self>,
14705    ) -> Result<()> {
14706        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14707
14708        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14709
14710        self.select_next_match_internal(&display_map, false, None, window, cx)?;
14711        let Some(select_next_state) = self.select_next_state.as_mut() else {
14712            return Ok(());
14713        };
14714        if select_next_state.done {
14715            return Ok(());
14716        }
14717
14718        let mut new_selections = Vec::new();
14719
14720        let reversed = self.selections.oldest::<usize>(&display_map).reversed;
14721        let buffer = display_map.buffer_snapshot();
14722        let query_matches = select_next_state
14723            .query
14724            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
14725
14726        for query_match in query_matches.into_iter() {
14727            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
14728            let offset_range = if reversed {
14729                query_match.end()..query_match.start()
14730            } else {
14731                query_match.start()..query_match.end()
14732            };
14733
14734            if !select_next_state.wordwise
14735                || (!buffer.is_inside_word(offset_range.start, None)
14736                    && !buffer.is_inside_word(offset_range.end, None))
14737            {
14738                new_selections.push(offset_range.start..offset_range.end);
14739            }
14740        }
14741
14742        select_next_state.done = true;
14743
14744        if new_selections.is_empty() {
14745            log::error!("bug: new_selections is empty in select_all_matches");
14746            return Ok(());
14747        }
14748
14749        self.unfold_ranges(&new_selections.clone(), false, false, cx);
14750        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
14751            selections.select_ranges(new_selections)
14752        });
14753
14754        Ok(())
14755    }
14756
14757    pub fn select_next(
14758        &mut self,
14759        action: &SelectNext,
14760        window: &mut Window,
14761        cx: &mut Context<Self>,
14762    ) -> Result<()> {
14763        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14764        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14765        self.select_next_match_internal(
14766            &display_map,
14767            action.replace_newest,
14768            Some(Autoscroll::newest()),
14769            window,
14770            cx,
14771        )?;
14772        Ok(())
14773    }
14774
14775    pub fn select_previous(
14776        &mut self,
14777        action: &SelectPrevious,
14778        window: &mut Window,
14779        cx: &mut Context<Self>,
14780    ) -> Result<()> {
14781        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14782        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14783        let buffer = display_map.buffer_snapshot();
14784        let mut selections = self.selections.all::<usize>(&display_map);
14785        if let Some(mut select_prev_state) = self.select_prev_state.take() {
14786            let query = &select_prev_state.query;
14787            if !select_prev_state.done {
14788                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14789                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14790                let mut next_selected_range = None;
14791                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
14792                let bytes_before_last_selection =
14793                    buffer.reversed_bytes_in_range(0..last_selection.start);
14794                let bytes_after_first_selection =
14795                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
14796                let query_matches = query
14797                    .stream_find_iter(bytes_before_last_selection)
14798                    .map(|result| (last_selection.start, result))
14799                    .chain(
14800                        query
14801                            .stream_find_iter(bytes_after_first_selection)
14802                            .map(|result| (buffer.len(), result)),
14803                    );
14804                for (end_offset, query_match) in query_matches {
14805                    let query_match = query_match.unwrap(); // can only fail due to I/O
14806                    let offset_range =
14807                        end_offset - query_match.end()..end_offset - query_match.start();
14808
14809                    if !select_prev_state.wordwise
14810                        || (!buffer.is_inside_word(offset_range.start, None)
14811                            && !buffer.is_inside_word(offset_range.end, None))
14812                    {
14813                        next_selected_range = Some(offset_range);
14814                        break;
14815                    }
14816                }
14817
14818                if let Some(next_selected_range) = next_selected_range {
14819                    self.select_match_ranges(
14820                        next_selected_range,
14821                        last_selection.reversed,
14822                        action.replace_newest,
14823                        Some(Autoscroll::newest()),
14824                        window,
14825                        cx,
14826                    );
14827                } else {
14828                    select_prev_state.done = true;
14829                }
14830            }
14831
14832            self.select_prev_state = Some(select_prev_state);
14833        } else {
14834            let mut only_carets = true;
14835            let mut same_text_selected = true;
14836            let mut selected_text = None;
14837
14838            let mut selections_iter = selections.iter().peekable();
14839            while let Some(selection) = selections_iter.next() {
14840                if selection.start != selection.end {
14841                    only_carets = false;
14842                }
14843
14844                if same_text_selected {
14845                    if selected_text.is_none() {
14846                        selected_text =
14847                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14848                    }
14849
14850                    if let Some(next_selection) = selections_iter.peek() {
14851                        if next_selection.range().len() == selection.range().len() {
14852                            let next_selected_text = buffer
14853                                .text_for_range(next_selection.range())
14854                                .collect::<String>();
14855                            if Some(next_selected_text) != selected_text {
14856                                same_text_selected = false;
14857                                selected_text = None;
14858                            }
14859                        } else {
14860                            same_text_selected = false;
14861                            selected_text = None;
14862                        }
14863                    }
14864                }
14865            }
14866
14867            if only_carets {
14868                for selection in &mut selections {
14869                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
14870                    selection.start = word_range.start;
14871                    selection.end = word_range.end;
14872                    selection.goal = SelectionGoal::None;
14873                    selection.reversed = false;
14874                    self.select_match_ranges(
14875                        selection.start..selection.end,
14876                        selection.reversed,
14877                        action.replace_newest,
14878                        Some(Autoscroll::newest()),
14879                        window,
14880                        cx,
14881                    );
14882                }
14883                if selections.len() == 1 {
14884                    let selection = selections
14885                        .last()
14886                        .expect("ensured that there's only one selection");
14887                    let query = buffer
14888                        .text_for_range(selection.start..selection.end)
14889                        .collect::<String>();
14890                    let is_empty = query.is_empty();
14891                    let select_state = SelectNextState {
14892                        query: self.build_query(&[query.chars().rev().collect::<String>()], cx)?,
14893                        wordwise: true,
14894                        done: is_empty,
14895                    };
14896                    self.select_prev_state = Some(select_state);
14897                } else {
14898                    self.select_prev_state = None;
14899                }
14900            } else if let Some(selected_text) = selected_text {
14901                self.select_prev_state = Some(SelectNextState {
14902                    query: self
14903                        .build_query(&[selected_text.chars().rev().collect::<String>()], cx)?,
14904                    wordwise: false,
14905                    done: false,
14906                });
14907                self.select_previous(action, window, cx)?;
14908            }
14909        }
14910        Ok(())
14911    }
14912
14913    /// Builds an `AhoCorasick` automaton from the provided patterns, while
14914    /// setting the case sensitivity based on the global
14915    /// `SelectNextCaseSensitive` setting, if set, otherwise based on the
14916    /// editor's settings.
14917    fn build_query<I, P>(&self, patterns: I, cx: &Context<Self>) -> Result<AhoCorasick, BuildError>
14918    where
14919        I: IntoIterator<Item = P>,
14920        P: AsRef<[u8]>,
14921    {
14922        let case_sensitive = self.select_next_is_case_sensitive.map_or_else(
14923            || EditorSettings::get_global(cx).search.case_sensitive,
14924            |value| value,
14925        );
14926
14927        let mut builder = AhoCorasickBuilder::new();
14928        builder.ascii_case_insensitive(!case_sensitive);
14929        builder.build(patterns)
14930    }
14931
14932    pub fn find_next_match(
14933        &mut self,
14934        _: &FindNextMatch,
14935        window: &mut Window,
14936        cx: &mut Context<Self>,
14937    ) -> Result<()> {
14938        let selections = self.selections.disjoint_anchors_arc();
14939        match selections.first() {
14940            Some(first) if selections.len() >= 2 => {
14941                self.change_selections(Default::default(), window, cx, |s| {
14942                    s.select_ranges([first.range()]);
14943                });
14944            }
14945            _ => self.select_next(
14946                &SelectNext {
14947                    replace_newest: true,
14948                },
14949                window,
14950                cx,
14951            )?,
14952        }
14953        Ok(())
14954    }
14955
14956    pub fn find_previous_match(
14957        &mut self,
14958        _: &FindPreviousMatch,
14959        window: &mut Window,
14960        cx: &mut Context<Self>,
14961    ) -> Result<()> {
14962        let selections = self.selections.disjoint_anchors_arc();
14963        match selections.last() {
14964            Some(last) if selections.len() >= 2 => {
14965                self.change_selections(Default::default(), window, cx, |s| {
14966                    s.select_ranges([last.range()]);
14967                });
14968            }
14969            _ => self.select_previous(
14970                &SelectPrevious {
14971                    replace_newest: true,
14972                },
14973                window,
14974                cx,
14975            )?,
14976        }
14977        Ok(())
14978    }
14979
14980    pub fn toggle_comments(
14981        &mut self,
14982        action: &ToggleComments,
14983        window: &mut Window,
14984        cx: &mut Context<Self>,
14985    ) {
14986        if self.read_only(cx) {
14987            return;
14988        }
14989        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14990        let text_layout_details = &self.text_layout_details(window);
14991        self.transact(window, cx, |this, window, cx| {
14992            let mut selections = this
14993                .selections
14994                .all::<MultiBufferPoint>(&this.display_snapshot(cx));
14995            let mut edits = Vec::new();
14996            let mut selection_edit_ranges = Vec::new();
14997            let mut last_toggled_row = None;
14998            let snapshot = this.buffer.read(cx).read(cx);
14999            let empty_str: Arc<str> = Arc::default();
15000            let mut suffixes_inserted = Vec::new();
15001            let ignore_indent = action.ignore_indent;
15002
15003            fn comment_prefix_range(
15004                snapshot: &MultiBufferSnapshot,
15005                row: MultiBufferRow,
15006                comment_prefix: &str,
15007                comment_prefix_whitespace: &str,
15008                ignore_indent: bool,
15009            ) -> Range<Point> {
15010                let indent_size = if ignore_indent {
15011                    0
15012                } else {
15013                    snapshot.indent_size_for_line(row).len
15014                };
15015
15016                let start = Point::new(row.0, indent_size);
15017
15018                let mut line_bytes = snapshot
15019                    .bytes_in_range(start..snapshot.max_point())
15020                    .flatten()
15021                    .copied();
15022
15023                // If this line currently begins with the line comment prefix, then record
15024                // the range containing the prefix.
15025                if line_bytes
15026                    .by_ref()
15027                    .take(comment_prefix.len())
15028                    .eq(comment_prefix.bytes())
15029                {
15030                    // Include any whitespace that matches the comment prefix.
15031                    let matching_whitespace_len = line_bytes
15032                        .zip(comment_prefix_whitespace.bytes())
15033                        .take_while(|(a, b)| a == b)
15034                        .count() as u32;
15035                    let end = Point::new(
15036                        start.row,
15037                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
15038                    );
15039                    start..end
15040                } else {
15041                    start..start
15042                }
15043            }
15044
15045            fn comment_suffix_range(
15046                snapshot: &MultiBufferSnapshot,
15047                row: MultiBufferRow,
15048                comment_suffix: &str,
15049                comment_suffix_has_leading_space: bool,
15050            ) -> Range<Point> {
15051                let end = Point::new(row.0, snapshot.line_len(row));
15052                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
15053
15054                let mut line_end_bytes = snapshot
15055                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
15056                    .flatten()
15057                    .copied();
15058
15059                let leading_space_len = if suffix_start_column > 0
15060                    && line_end_bytes.next() == Some(b' ')
15061                    && comment_suffix_has_leading_space
15062                {
15063                    1
15064                } else {
15065                    0
15066                };
15067
15068                // If this line currently begins with the line comment prefix, then record
15069                // the range containing the prefix.
15070                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
15071                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
15072                    start..end
15073                } else {
15074                    end..end
15075                }
15076            }
15077
15078            // TODO: Handle selections that cross excerpts
15079            for selection in &mut selections {
15080                let start_column = snapshot
15081                    .indent_size_for_line(MultiBufferRow(selection.start.row))
15082                    .len;
15083                let language = if let Some(language) =
15084                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
15085                {
15086                    language
15087                } else {
15088                    continue;
15089                };
15090
15091                selection_edit_ranges.clear();
15092
15093                // If multiple selections contain a given row, avoid processing that
15094                // row more than once.
15095                let mut start_row = MultiBufferRow(selection.start.row);
15096                if last_toggled_row == Some(start_row) {
15097                    start_row = start_row.next_row();
15098                }
15099                let end_row =
15100                    if selection.end.row > selection.start.row && selection.end.column == 0 {
15101                        MultiBufferRow(selection.end.row - 1)
15102                    } else {
15103                        MultiBufferRow(selection.end.row)
15104                    };
15105                last_toggled_row = Some(end_row);
15106
15107                if start_row > end_row {
15108                    continue;
15109                }
15110
15111                // If the language has line comments, toggle those.
15112                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
15113
15114                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
15115                if ignore_indent {
15116                    full_comment_prefixes = full_comment_prefixes
15117                        .into_iter()
15118                        .map(|s| Arc::from(s.trim_end()))
15119                        .collect();
15120                }
15121
15122                if !full_comment_prefixes.is_empty() {
15123                    let first_prefix = full_comment_prefixes
15124                        .first()
15125                        .expect("prefixes is non-empty");
15126                    let prefix_trimmed_lengths = full_comment_prefixes
15127                        .iter()
15128                        .map(|p| p.trim_end_matches(' ').len())
15129                        .collect::<SmallVec<[usize; 4]>>();
15130
15131                    let mut all_selection_lines_are_comments = true;
15132
15133                    for row in start_row.0..=end_row.0 {
15134                        let row = MultiBufferRow(row);
15135                        if start_row < end_row && snapshot.is_line_blank(row) {
15136                            continue;
15137                        }
15138
15139                        let prefix_range = full_comment_prefixes
15140                            .iter()
15141                            .zip(prefix_trimmed_lengths.iter().copied())
15142                            .map(|(prefix, trimmed_prefix_len)| {
15143                                comment_prefix_range(
15144                                    snapshot.deref(),
15145                                    row,
15146                                    &prefix[..trimmed_prefix_len],
15147                                    &prefix[trimmed_prefix_len..],
15148                                    ignore_indent,
15149                                )
15150                            })
15151                            .max_by_key(|range| range.end.column - range.start.column)
15152                            .expect("prefixes is non-empty");
15153
15154                        if prefix_range.is_empty() {
15155                            all_selection_lines_are_comments = false;
15156                        }
15157
15158                        selection_edit_ranges.push(prefix_range);
15159                    }
15160
15161                    if all_selection_lines_are_comments {
15162                        edits.extend(
15163                            selection_edit_ranges
15164                                .iter()
15165                                .cloned()
15166                                .map(|range| (range, empty_str.clone())),
15167                        );
15168                    } else {
15169                        let min_column = selection_edit_ranges
15170                            .iter()
15171                            .map(|range| range.start.column)
15172                            .min()
15173                            .unwrap_or(0);
15174                        edits.extend(selection_edit_ranges.iter().map(|range| {
15175                            let position = Point::new(range.start.row, min_column);
15176                            (position..position, first_prefix.clone())
15177                        }));
15178                    }
15179                } else if let Some(BlockCommentConfig {
15180                    start: full_comment_prefix,
15181                    end: comment_suffix,
15182                    ..
15183                }) = language.block_comment()
15184                {
15185                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
15186                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
15187                    let prefix_range = comment_prefix_range(
15188                        snapshot.deref(),
15189                        start_row,
15190                        comment_prefix,
15191                        comment_prefix_whitespace,
15192                        ignore_indent,
15193                    );
15194                    let suffix_range = comment_suffix_range(
15195                        snapshot.deref(),
15196                        end_row,
15197                        comment_suffix.trim_start_matches(' '),
15198                        comment_suffix.starts_with(' '),
15199                    );
15200
15201                    if prefix_range.is_empty() || suffix_range.is_empty() {
15202                        edits.push((
15203                            prefix_range.start..prefix_range.start,
15204                            full_comment_prefix.clone(),
15205                        ));
15206                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
15207                        suffixes_inserted.push((end_row, comment_suffix.len()));
15208                    } else {
15209                        edits.push((prefix_range, empty_str.clone()));
15210                        edits.push((suffix_range, empty_str.clone()));
15211                    }
15212                } else {
15213                    continue;
15214                }
15215            }
15216
15217            drop(snapshot);
15218            this.buffer.update(cx, |buffer, cx| {
15219                buffer.edit(edits, None, cx);
15220            });
15221
15222            // Adjust selections so that they end before any comment suffixes that
15223            // were inserted.
15224            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
15225            let mut selections = this.selections.all::<Point>(&this.display_snapshot(cx));
15226            let snapshot = this.buffer.read(cx).read(cx);
15227            for selection in &mut selections {
15228                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
15229                    match row.cmp(&MultiBufferRow(selection.end.row)) {
15230                        Ordering::Less => {
15231                            suffixes_inserted.next();
15232                            continue;
15233                        }
15234                        Ordering::Greater => break,
15235                        Ordering::Equal => {
15236                            if selection.end.column == snapshot.line_len(row) {
15237                                if selection.is_empty() {
15238                                    selection.start.column -= suffix_len as u32;
15239                                }
15240                                selection.end.column -= suffix_len as u32;
15241                            }
15242                            break;
15243                        }
15244                    }
15245                }
15246            }
15247
15248            drop(snapshot);
15249            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
15250
15251            let selections = this.selections.all::<Point>(&this.display_snapshot(cx));
15252            let selections_on_single_row = selections.windows(2).all(|selections| {
15253                selections[0].start.row == selections[1].start.row
15254                    && selections[0].end.row == selections[1].end.row
15255                    && selections[0].start.row == selections[0].end.row
15256            });
15257            let selections_selecting = selections
15258                .iter()
15259                .any(|selection| selection.start != selection.end);
15260            let advance_downwards = action.advance_downwards
15261                && selections_on_single_row
15262                && !selections_selecting
15263                && !matches!(this.mode, EditorMode::SingleLine);
15264
15265            if advance_downwards {
15266                let snapshot = this.buffer.read(cx).snapshot(cx);
15267
15268                this.change_selections(Default::default(), window, cx, |s| {
15269                    s.move_cursors_with(|display_snapshot, display_point, _| {
15270                        let mut point = display_point.to_point(display_snapshot);
15271                        point.row += 1;
15272                        point = snapshot.clip_point(point, Bias::Left);
15273                        let display_point = point.to_display_point(display_snapshot);
15274                        let goal = SelectionGoal::HorizontalPosition(
15275                            display_snapshot
15276                                .x_for_display_point(display_point, text_layout_details)
15277                                .into(),
15278                        );
15279                        (display_point, goal)
15280                    })
15281                });
15282            }
15283        });
15284    }
15285
15286    pub fn select_enclosing_symbol(
15287        &mut self,
15288        _: &SelectEnclosingSymbol,
15289        window: &mut Window,
15290        cx: &mut Context<Self>,
15291    ) {
15292        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15293
15294        let buffer = self.buffer.read(cx).snapshot(cx);
15295        let old_selections = self
15296            .selections
15297            .all::<usize>(&self.display_snapshot(cx))
15298            .into_boxed_slice();
15299
15300        fn update_selection(
15301            selection: &Selection<usize>,
15302            buffer_snap: &MultiBufferSnapshot,
15303        ) -> Option<Selection<usize>> {
15304            let cursor = selection.head();
15305            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
15306            for symbol in symbols.iter().rev() {
15307                let start = symbol.range.start.to_offset(buffer_snap);
15308                let end = symbol.range.end.to_offset(buffer_snap);
15309                let new_range = start..end;
15310                if start < selection.start || end > selection.end {
15311                    return Some(Selection {
15312                        id: selection.id,
15313                        start: new_range.start,
15314                        end: new_range.end,
15315                        goal: SelectionGoal::None,
15316                        reversed: selection.reversed,
15317                    });
15318                }
15319            }
15320            None
15321        }
15322
15323        let mut selected_larger_symbol = false;
15324        let new_selections = old_selections
15325            .iter()
15326            .map(|selection| match update_selection(selection, &buffer) {
15327                Some(new_selection) => {
15328                    if new_selection.range() != selection.range() {
15329                        selected_larger_symbol = true;
15330                    }
15331                    new_selection
15332                }
15333                None => selection.clone(),
15334            })
15335            .collect::<Vec<_>>();
15336
15337        if selected_larger_symbol {
15338            self.change_selections(Default::default(), window, cx, |s| {
15339                s.select(new_selections);
15340            });
15341        }
15342    }
15343
15344    pub fn select_larger_syntax_node(
15345        &mut self,
15346        _: &SelectLargerSyntaxNode,
15347        window: &mut Window,
15348        cx: &mut Context<Self>,
15349    ) {
15350        let Some(visible_row_count) = self.visible_row_count() else {
15351            return;
15352        };
15353        let old_selections: Box<[_]> = self
15354            .selections
15355            .all::<usize>(&self.display_snapshot(cx))
15356            .into();
15357        if old_selections.is_empty() {
15358            return;
15359        }
15360
15361        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15362
15363        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15364        let buffer = self.buffer.read(cx).snapshot(cx);
15365
15366        let mut selected_larger_node = false;
15367        let mut new_selections = old_selections
15368            .iter()
15369            .map(|selection| {
15370                let old_range = selection.start..selection.end;
15371
15372                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
15373                    // manually select word at selection
15374                    if ["string_content", "inline"].contains(&node.kind()) {
15375                        let (word_range, _) = buffer.surrounding_word(old_range.start, None);
15376                        // ignore if word is already selected
15377                        if !word_range.is_empty() && old_range != word_range {
15378                            let (last_word_range, _) = buffer.surrounding_word(old_range.end, None);
15379                            // only select word if start and end point belongs to same word
15380                            if word_range == last_word_range {
15381                                selected_larger_node = true;
15382                                return Selection {
15383                                    id: selection.id,
15384                                    start: word_range.start,
15385                                    end: word_range.end,
15386                                    goal: SelectionGoal::None,
15387                                    reversed: selection.reversed,
15388                                };
15389                            }
15390                        }
15391                    }
15392                }
15393
15394                let mut new_range = old_range.clone();
15395                while let Some((node, range)) = buffer.syntax_ancestor(new_range.clone()) {
15396                    new_range = range;
15397                    if !node.is_named() {
15398                        continue;
15399                    }
15400                    if !display_map.intersects_fold(new_range.start)
15401                        && !display_map.intersects_fold(new_range.end)
15402                    {
15403                        break;
15404                    }
15405                }
15406
15407                selected_larger_node |= new_range != old_range;
15408                Selection {
15409                    id: selection.id,
15410                    start: new_range.start,
15411                    end: new_range.end,
15412                    goal: SelectionGoal::None,
15413                    reversed: selection.reversed,
15414                }
15415            })
15416            .collect::<Vec<_>>();
15417
15418        if !selected_larger_node {
15419            return; // don't put this call in the history
15420        }
15421
15422        // scroll based on transformation done to the last selection created by the user
15423        let (last_old, last_new) = old_selections
15424            .last()
15425            .zip(new_selections.last().cloned())
15426            .expect("old_selections isn't empty");
15427
15428        // revert selection
15429        let is_selection_reversed = {
15430            let should_newest_selection_be_reversed = last_old.start != last_new.start;
15431            new_selections.last_mut().expect("checked above").reversed =
15432                should_newest_selection_be_reversed;
15433            should_newest_selection_be_reversed
15434        };
15435
15436        if selected_larger_node {
15437            self.select_syntax_node_history.disable_clearing = true;
15438            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15439                s.select(new_selections.clone());
15440            });
15441            self.select_syntax_node_history.disable_clearing = false;
15442        }
15443
15444        let start_row = last_new.start.to_display_point(&display_map).row().0;
15445        let end_row = last_new.end.to_display_point(&display_map).row().0;
15446        let selection_height = end_row - start_row + 1;
15447        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
15448
15449        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
15450        let scroll_behavior = if fits_on_the_screen {
15451            self.request_autoscroll(Autoscroll::fit(), cx);
15452            SelectSyntaxNodeScrollBehavior::FitSelection
15453        } else if is_selection_reversed {
15454            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15455            SelectSyntaxNodeScrollBehavior::CursorTop
15456        } else {
15457            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15458            SelectSyntaxNodeScrollBehavior::CursorBottom
15459        };
15460
15461        self.select_syntax_node_history.push((
15462            old_selections,
15463            scroll_behavior,
15464            is_selection_reversed,
15465        ));
15466    }
15467
15468    pub fn select_smaller_syntax_node(
15469        &mut self,
15470        _: &SelectSmallerSyntaxNode,
15471        window: &mut Window,
15472        cx: &mut Context<Self>,
15473    ) {
15474        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15475
15476        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
15477            self.select_syntax_node_history.pop()
15478        {
15479            if let Some(selection) = selections.last_mut() {
15480                selection.reversed = is_selection_reversed;
15481            }
15482
15483            self.select_syntax_node_history.disable_clearing = true;
15484            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15485                s.select(selections.to_vec());
15486            });
15487            self.select_syntax_node_history.disable_clearing = false;
15488
15489            match scroll_behavior {
15490                SelectSyntaxNodeScrollBehavior::CursorTop => {
15491                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15492                }
15493                SelectSyntaxNodeScrollBehavior::FitSelection => {
15494                    self.request_autoscroll(Autoscroll::fit(), cx);
15495                }
15496                SelectSyntaxNodeScrollBehavior::CursorBottom => {
15497                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15498                }
15499            }
15500        }
15501    }
15502
15503    pub fn unwrap_syntax_node(
15504        &mut self,
15505        _: &UnwrapSyntaxNode,
15506        window: &mut Window,
15507        cx: &mut Context<Self>,
15508    ) {
15509        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15510
15511        let buffer = self.buffer.read(cx).snapshot(cx);
15512        let selections = self
15513            .selections
15514            .all::<usize>(&self.display_snapshot(cx))
15515            .into_iter()
15516            // subtracting the offset requires sorting
15517            .sorted_by_key(|i| i.start);
15518
15519        let full_edits = selections
15520            .into_iter()
15521            .filter_map(|selection| {
15522                let child = if selection.is_empty()
15523                    && let Some((_, ancestor_range)) =
15524                        buffer.syntax_ancestor(selection.start..selection.end)
15525                {
15526                    ancestor_range
15527                } else {
15528                    selection.range()
15529                };
15530
15531                let mut parent = child.clone();
15532                while let Some((_, ancestor_range)) = buffer.syntax_ancestor(parent.clone()) {
15533                    parent = ancestor_range;
15534                    if parent.start < child.start || parent.end > child.end {
15535                        break;
15536                    }
15537                }
15538
15539                if parent == child {
15540                    return None;
15541                }
15542                let text = buffer.text_for_range(child).collect::<String>();
15543                Some((selection.id, parent, text))
15544            })
15545            .collect::<Vec<_>>();
15546        if full_edits.is_empty() {
15547            return;
15548        }
15549
15550        self.transact(window, cx, |this, window, cx| {
15551            this.buffer.update(cx, |buffer, cx| {
15552                buffer.edit(
15553                    full_edits
15554                        .iter()
15555                        .map(|(_, p, t)| (p.clone(), t.clone()))
15556                        .collect::<Vec<_>>(),
15557                    None,
15558                    cx,
15559                );
15560            });
15561            this.change_selections(Default::default(), window, cx, |s| {
15562                let mut offset = 0;
15563                let mut selections = vec![];
15564                for (id, parent, text) in full_edits {
15565                    let start = parent.start - offset;
15566                    offset += parent.len() - text.len();
15567                    selections.push(Selection {
15568                        id,
15569                        start,
15570                        end: start + text.len(),
15571                        reversed: false,
15572                        goal: Default::default(),
15573                    });
15574                }
15575                s.select(selections);
15576            });
15577        });
15578    }
15579
15580    pub fn select_next_syntax_node(
15581        &mut self,
15582        _: &SelectNextSyntaxNode,
15583        window: &mut Window,
15584        cx: &mut Context<Self>,
15585    ) {
15586        let old_selections: Box<[_]> = self
15587            .selections
15588            .all::<usize>(&self.display_snapshot(cx))
15589            .into();
15590        if old_selections.is_empty() {
15591            return;
15592        }
15593
15594        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15595
15596        let buffer = self.buffer.read(cx).snapshot(cx);
15597        let mut selected_sibling = false;
15598
15599        let new_selections = old_selections
15600            .iter()
15601            .map(|selection| {
15602                let old_range = selection.start..selection.end;
15603
15604                if let Some(node) = buffer.syntax_next_sibling(old_range) {
15605                    let new_range = node.byte_range();
15606                    selected_sibling = true;
15607                    Selection {
15608                        id: selection.id,
15609                        start: new_range.start,
15610                        end: new_range.end,
15611                        goal: SelectionGoal::None,
15612                        reversed: selection.reversed,
15613                    }
15614                } else {
15615                    selection.clone()
15616                }
15617            })
15618            .collect::<Vec<_>>();
15619
15620        if selected_sibling {
15621            self.change_selections(
15622                SelectionEffects::scroll(Autoscroll::fit()),
15623                window,
15624                cx,
15625                |s| {
15626                    s.select(new_selections);
15627                },
15628            );
15629        }
15630    }
15631
15632    pub fn select_prev_syntax_node(
15633        &mut self,
15634        _: &SelectPreviousSyntaxNode,
15635        window: &mut Window,
15636        cx: &mut Context<Self>,
15637    ) {
15638        let old_selections: Box<[_]> = self
15639            .selections
15640            .all::<usize>(&self.display_snapshot(cx))
15641            .into();
15642        if old_selections.is_empty() {
15643            return;
15644        }
15645
15646        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15647
15648        let buffer = self.buffer.read(cx).snapshot(cx);
15649        let mut selected_sibling = false;
15650
15651        let new_selections = old_selections
15652            .iter()
15653            .map(|selection| {
15654                let old_range = selection.start..selection.end;
15655
15656                if let Some(node) = buffer.syntax_prev_sibling(old_range) {
15657                    let new_range = node.byte_range();
15658                    selected_sibling = true;
15659                    Selection {
15660                        id: selection.id,
15661                        start: new_range.start,
15662                        end: new_range.end,
15663                        goal: SelectionGoal::None,
15664                        reversed: selection.reversed,
15665                    }
15666                } else {
15667                    selection.clone()
15668                }
15669            })
15670            .collect::<Vec<_>>();
15671
15672        if selected_sibling {
15673            self.change_selections(
15674                SelectionEffects::scroll(Autoscroll::fit()),
15675                window,
15676                cx,
15677                |s| {
15678                    s.select(new_selections);
15679                },
15680            );
15681        }
15682    }
15683
15684    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
15685        if !EditorSettings::get_global(cx).gutter.runnables {
15686            self.clear_tasks();
15687            return Task::ready(());
15688        }
15689        let project = self.project().map(Entity::downgrade);
15690        let task_sources = self.lsp_task_sources(cx);
15691        let multi_buffer = self.buffer.downgrade();
15692        cx.spawn_in(window, async move |editor, cx| {
15693            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
15694            let Some(project) = project.and_then(|p| p.upgrade()) else {
15695                return;
15696            };
15697            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
15698                this.display_map.update(cx, |map, cx| map.snapshot(cx))
15699            }) else {
15700                return;
15701            };
15702
15703            let hide_runnables = project
15704                .update(cx, |project, _| project.is_via_collab())
15705                .unwrap_or(true);
15706            if hide_runnables {
15707                return;
15708            }
15709            let new_rows =
15710                cx.background_spawn({
15711                    let snapshot = display_snapshot.clone();
15712                    async move {
15713                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
15714                    }
15715                })
15716                    .await;
15717            let Ok(lsp_tasks) =
15718                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
15719            else {
15720                return;
15721            };
15722            let lsp_tasks = lsp_tasks.await;
15723
15724            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
15725                lsp_tasks
15726                    .into_iter()
15727                    .flat_map(|(kind, tasks)| {
15728                        tasks.into_iter().filter_map(move |(location, task)| {
15729                            Some((kind.clone(), location?, task))
15730                        })
15731                    })
15732                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
15733                        let buffer = location.target.buffer;
15734                        let buffer_snapshot = buffer.read(cx).snapshot();
15735                        let offset = display_snapshot.buffer_snapshot().excerpts().find_map(
15736                            |(excerpt_id, snapshot, _)| {
15737                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
15738                                    display_snapshot
15739                                        .buffer_snapshot()
15740                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
15741                                } else {
15742                                    None
15743                                }
15744                            },
15745                        );
15746                        if let Some(offset) = offset {
15747                            let task_buffer_range =
15748                                location.target.range.to_point(&buffer_snapshot);
15749                            let context_buffer_range =
15750                                task_buffer_range.to_offset(&buffer_snapshot);
15751                            let context_range = BufferOffset(context_buffer_range.start)
15752                                ..BufferOffset(context_buffer_range.end);
15753
15754                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
15755                                .or_insert_with(|| RunnableTasks {
15756                                    templates: Vec::new(),
15757                                    offset,
15758                                    column: task_buffer_range.start.column,
15759                                    extra_variables: HashMap::default(),
15760                                    context_range,
15761                                })
15762                                .templates
15763                                .push((kind, task.original_task().clone()));
15764                        }
15765
15766                        acc
15767                    })
15768            }) else {
15769                return;
15770            };
15771
15772            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
15773                buffer.language_settings(cx).tasks.prefer_lsp
15774            }) else {
15775                return;
15776            };
15777
15778            let rows = Self::runnable_rows(
15779                project,
15780                display_snapshot,
15781                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
15782                new_rows,
15783                cx.clone(),
15784            )
15785            .await;
15786            editor
15787                .update(cx, |editor, _| {
15788                    editor.clear_tasks();
15789                    for (key, mut value) in rows {
15790                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
15791                            value.templates.extend(lsp_tasks.templates);
15792                        }
15793
15794                        editor.insert_tasks(key, value);
15795                    }
15796                    for (key, value) in lsp_tasks_by_rows {
15797                        editor.insert_tasks(key, value);
15798                    }
15799                })
15800                .ok();
15801        })
15802    }
15803    fn fetch_runnable_ranges(
15804        snapshot: &DisplaySnapshot,
15805        range: Range<Anchor>,
15806    ) -> Vec<language::RunnableRange> {
15807        snapshot.buffer_snapshot().runnable_ranges(range).collect()
15808    }
15809
15810    fn runnable_rows(
15811        project: Entity<Project>,
15812        snapshot: DisplaySnapshot,
15813        prefer_lsp: bool,
15814        runnable_ranges: Vec<RunnableRange>,
15815        cx: AsyncWindowContext,
15816    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
15817        cx.spawn(async move |cx| {
15818            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
15819            for mut runnable in runnable_ranges {
15820                let Some(tasks) = cx
15821                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
15822                    .ok()
15823                else {
15824                    continue;
15825                };
15826                let mut tasks = tasks.await;
15827
15828                if prefer_lsp {
15829                    tasks.retain(|(task_kind, _)| {
15830                        !matches!(task_kind, TaskSourceKind::Language { .. })
15831                    });
15832                }
15833                if tasks.is_empty() {
15834                    continue;
15835                }
15836
15837                let point = runnable
15838                    .run_range
15839                    .start
15840                    .to_point(&snapshot.buffer_snapshot());
15841                let Some(row) = snapshot
15842                    .buffer_snapshot()
15843                    .buffer_line_for_row(MultiBufferRow(point.row))
15844                    .map(|(_, range)| range.start.row)
15845                else {
15846                    continue;
15847                };
15848
15849                let context_range =
15850                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
15851                runnable_rows.push((
15852                    (runnable.buffer_id, row),
15853                    RunnableTasks {
15854                        templates: tasks,
15855                        offset: snapshot
15856                            .buffer_snapshot()
15857                            .anchor_before(runnable.run_range.start),
15858                        context_range,
15859                        column: point.column,
15860                        extra_variables: runnable.extra_captures,
15861                    },
15862                ));
15863            }
15864            runnable_rows
15865        })
15866    }
15867
15868    fn templates_with_tags(
15869        project: &Entity<Project>,
15870        runnable: &mut Runnable,
15871        cx: &mut App,
15872    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
15873        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
15874            let (worktree_id, file) = project
15875                .buffer_for_id(runnable.buffer, cx)
15876                .and_then(|buffer| buffer.read(cx).file())
15877                .map(|file| (file.worktree_id(cx), file.clone()))
15878                .unzip();
15879
15880            (
15881                project.task_store().read(cx).task_inventory().cloned(),
15882                worktree_id,
15883                file,
15884            )
15885        });
15886
15887        let tags = mem::take(&mut runnable.tags);
15888        let language = runnable.language.clone();
15889        cx.spawn(async move |cx| {
15890            let mut templates_with_tags = Vec::new();
15891            if let Some(inventory) = inventory {
15892                for RunnableTag(tag) in tags {
15893                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
15894                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
15895                    }) else {
15896                        return templates_with_tags;
15897                    };
15898                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
15899                        move |(_, template)| {
15900                            template.tags.iter().any(|source_tag| source_tag == &tag)
15901                        },
15902                    ));
15903                }
15904            }
15905            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
15906
15907            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
15908                // Strongest source wins; if we have worktree tag binding, prefer that to
15909                // global and language bindings;
15910                // if we have a global binding, prefer that to language binding.
15911                let first_mismatch = templates_with_tags
15912                    .iter()
15913                    .position(|(tag_source, _)| tag_source != leading_tag_source);
15914                if let Some(index) = first_mismatch {
15915                    templates_with_tags.truncate(index);
15916                }
15917            }
15918
15919            templates_with_tags
15920        })
15921    }
15922
15923    pub fn move_to_enclosing_bracket(
15924        &mut self,
15925        _: &MoveToEnclosingBracket,
15926        window: &mut Window,
15927        cx: &mut Context<Self>,
15928    ) {
15929        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15930        self.change_selections(Default::default(), window, cx, |s| {
15931            s.move_offsets_with(|snapshot, selection| {
15932                let Some(enclosing_bracket_ranges) =
15933                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
15934                else {
15935                    return;
15936                };
15937
15938                let mut best_length = usize::MAX;
15939                let mut best_inside = false;
15940                let mut best_in_bracket_range = false;
15941                let mut best_destination = None;
15942                for (open, close) in enclosing_bracket_ranges {
15943                    let close = close.to_inclusive();
15944                    let length = close.end() - open.start;
15945                    let inside = selection.start >= open.end && selection.end <= *close.start();
15946                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
15947                        || close.contains(&selection.head());
15948
15949                    // If best is next to a bracket and current isn't, skip
15950                    if !in_bracket_range && best_in_bracket_range {
15951                        continue;
15952                    }
15953
15954                    // Prefer smaller lengths unless best is inside and current isn't
15955                    if length > best_length && (best_inside || !inside) {
15956                        continue;
15957                    }
15958
15959                    best_length = length;
15960                    best_inside = inside;
15961                    best_in_bracket_range = in_bracket_range;
15962                    best_destination = Some(
15963                        if close.contains(&selection.start) && close.contains(&selection.end) {
15964                            if inside { open.end } else { open.start }
15965                        } else if inside {
15966                            *close.start()
15967                        } else {
15968                            *close.end()
15969                        },
15970                    );
15971                }
15972
15973                if let Some(destination) = best_destination {
15974                    selection.collapse_to(destination, SelectionGoal::None);
15975                }
15976            })
15977        });
15978    }
15979
15980    pub fn undo_selection(
15981        &mut self,
15982        _: &UndoSelection,
15983        window: &mut Window,
15984        cx: &mut Context<Self>,
15985    ) {
15986        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15987        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
15988            self.selection_history.mode = SelectionHistoryMode::Undoing;
15989            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15990                this.end_selection(window, cx);
15991                this.change_selections(
15992                    SelectionEffects::scroll(Autoscroll::newest()),
15993                    window,
15994                    cx,
15995                    |s| s.select_anchors(entry.selections.to_vec()),
15996                );
15997            });
15998            self.selection_history.mode = SelectionHistoryMode::Normal;
15999
16000            self.select_next_state = entry.select_next_state;
16001            self.select_prev_state = entry.select_prev_state;
16002            self.add_selections_state = entry.add_selections_state;
16003        }
16004    }
16005
16006    pub fn redo_selection(
16007        &mut self,
16008        _: &RedoSelection,
16009        window: &mut Window,
16010        cx: &mut Context<Self>,
16011    ) {
16012        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16013        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
16014            self.selection_history.mode = SelectionHistoryMode::Redoing;
16015            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
16016                this.end_selection(window, cx);
16017                this.change_selections(
16018                    SelectionEffects::scroll(Autoscroll::newest()),
16019                    window,
16020                    cx,
16021                    |s| s.select_anchors(entry.selections.to_vec()),
16022                );
16023            });
16024            self.selection_history.mode = SelectionHistoryMode::Normal;
16025
16026            self.select_next_state = entry.select_next_state;
16027            self.select_prev_state = entry.select_prev_state;
16028            self.add_selections_state = entry.add_selections_state;
16029        }
16030    }
16031
16032    pub fn expand_excerpts(
16033        &mut self,
16034        action: &ExpandExcerpts,
16035        _: &mut Window,
16036        cx: &mut Context<Self>,
16037    ) {
16038        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
16039    }
16040
16041    pub fn expand_excerpts_down(
16042        &mut self,
16043        action: &ExpandExcerptsDown,
16044        _: &mut Window,
16045        cx: &mut Context<Self>,
16046    ) {
16047        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
16048    }
16049
16050    pub fn expand_excerpts_up(
16051        &mut self,
16052        action: &ExpandExcerptsUp,
16053        _: &mut Window,
16054        cx: &mut Context<Self>,
16055    ) {
16056        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
16057    }
16058
16059    pub fn expand_excerpts_for_direction(
16060        &mut self,
16061        lines: u32,
16062        direction: ExpandExcerptDirection,
16063
16064        cx: &mut Context<Self>,
16065    ) {
16066        let selections = self.selections.disjoint_anchors_arc();
16067
16068        let lines = if lines == 0 {
16069            EditorSettings::get_global(cx).expand_excerpt_lines
16070        } else {
16071            lines
16072        };
16073
16074        self.buffer.update(cx, |buffer, cx| {
16075            let snapshot = buffer.snapshot(cx);
16076            let mut excerpt_ids = selections
16077                .iter()
16078                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
16079                .collect::<Vec<_>>();
16080            excerpt_ids.sort();
16081            excerpt_ids.dedup();
16082            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
16083        })
16084    }
16085
16086    pub fn expand_excerpt(
16087        &mut self,
16088        excerpt: ExcerptId,
16089        direction: ExpandExcerptDirection,
16090        window: &mut Window,
16091        cx: &mut Context<Self>,
16092    ) {
16093        let current_scroll_position = self.scroll_position(cx);
16094        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
16095        let mut scroll = None;
16096
16097        if direction == ExpandExcerptDirection::Down {
16098            let multi_buffer = self.buffer.read(cx);
16099            let snapshot = multi_buffer.snapshot(cx);
16100            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt)
16101                && let Some(buffer) = multi_buffer.buffer(buffer_id)
16102                && let Some(excerpt_range) = snapshot.context_range_for_excerpt(excerpt)
16103            {
16104                let buffer_snapshot = buffer.read(cx).snapshot();
16105                let excerpt_end_row = Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
16106                let last_row = buffer_snapshot.max_point().row;
16107                let lines_below = last_row.saturating_sub(excerpt_end_row);
16108                if lines_below >= lines_to_expand {
16109                    scroll = Some(
16110                        current_scroll_position
16111                            + gpui::Point::new(0.0, lines_to_expand as ScrollOffset),
16112                    );
16113                }
16114            }
16115        }
16116        if direction == ExpandExcerptDirection::Up
16117            && self
16118                .buffer
16119                .read(cx)
16120                .snapshot(cx)
16121                .excerpt_before(excerpt)
16122                .is_none()
16123        {
16124            scroll = Some(current_scroll_position);
16125        }
16126
16127        self.buffer.update(cx, |buffer, cx| {
16128            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
16129        });
16130
16131        if let Some(new_scroll_position) = scroll {
16132            self.set_scroll_position(new_scroll_position, window, cx);
16133        }
16134    }
16135
16136    pub fn go_to_singleton_buffer_point(
16137        &mut self,
16138        point: Point,
16139        window: &mut Window,
16140        cx: &mut Context<Self>,
16141    ) {
16142        self.go_to_singleton_buffer_range(point..point, window, cx);
16143    }
16144
16145    pub fn go_to_singleton_buffer_range(
16146        &mut self,
16147        range: Range<Point>,
16148        window: &mut Window,
16149        cx: &mut Context<Self>,
16150    ) {
16151        let multibuffer = self.buffer().read(cx);
16152        let Some(buffer) = multibuffer.as_singleton() else {
16153            return;
16154        };
16155        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
16156            return;
16157        };
16158        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
16159            return;
16160        };
16161        self.change_selections(
16162            SelectionEffects::default().nav_history(true),
16163            window,
16164            cx,
16165            |s| s.select_anchor_ranges([start..end]),
16166        );
16167    }
16168
16169    pub fn go_to_diagnostic(
16170        &mut self,
16171        action: &GoToDiagnostic,
16172        window: &mut Window,
16173        cx: &mut Context<Self>,
16174    ) {
16175        if !self.diagnostics_enabled() {
16176            return;
16177        }
16178        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16179        self.go_to_diagnostic_impl(Direction::Next, action.severity, window, cx)
16180    }
16181
16182    pub fn go_to_prev_diagnostic(
16183        &mut self,
16184        action: &GoToPreviousDiagnostic,
16185        window: &mut Window,
16186        cx: &mut Context<Self>,
16187    ) {
16188        if !self.diagnostics_enabled() {
16189            return;
16190        }
16191        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16192        self.go_to_diagnostic_impl(Direction::Prev, action.severity, window, cx)
16193    }
16194
16195    pub fn go_to_diagnostic_impl(
16196        &mut self,
16197        direction: Direction,
16198        severity: GoToDiagnosticSeverityFilter,
16199        window: &mut Window,
16200        cx: &mut Context<Self>,
16201    ) {
16202        let buffer = self.buffer.read(cx).snapshot(cx);
16203        let selection = self.selections.newest::<usize>(&self.display_snapshot(cx));
16204
16205        let mut active_group_id = None;
16206        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics
16207            && active_group.active_range.start.to_offset(&buffer) == selection.start
16208        {
16209            active_group_id = Some(active_group.group_id);
16210        }
16211
16212        fn filtered<'a>(
16213            severity: GoToDiagnosticSeverityFilter,
16214            diagnostics: impl Iterator<Item = DiagnosticEntryRef<'a, usize>>,
16215        ) -> impl Iterator<Item = DiagnosticEntryRef<'a, usize>> {
16216            diagnostics
16217                .filter(move |entry| severity.matches(entry.diagnostic.severity))
16218                .filter(|entry| entry.range.start != entry.range.end)
16219                .filter(|entry| !entry.diagnostic.is_unnecessary)
16220        }
16221
16222        let before = filtered(
16223            severity,
16224            buffer
16225                .diagnostics_in_range(0..selection.start)
16226                .filter(|entry| entry.range.start <= selection.start),
16227        );
16228        let after = filtered(
16229            severity,
16230            buffer
16231                .diagnostics_in_range(selection.start..buffer.len())
16232                .filter(|entry| entry.range.start >= selection.start),
16233        );
16234
16235        let mut found: Option<DiagnosticEntryRef<usize>> = None;
16236        if direction == Direction::Prev {
16237            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
16238            {
16239                for diagnostic in prev_diagnostics.into_iter().rev() {
16240                    if diagnostic.range.start != selection.start
16241                        || active_group_id
16242                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
16243                    {
16244                        found = Some(diagnostic);
16245                        break 'outer;
16246                    }
16247                }
16248            }
16249        } else {
16250            for diagnostic in after.chain(before) {
16251                if diagnostic.range.start != selection.start
16252                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
16253                {
16254                    found = Some(diagnostic);
16255                    break;
16256                }
16257            }
16258        }
16259        let Some(next_diagnostic) = found else {
16260            return;
16261        };
16262
16263        let next_diagnostic_start = buffer.anchor_after(next_diagnostic.range.start);
16264        let Some(buffer_id) = buffer.buffer_id_for_anchor(next_diagnostic_start) else {
16265            return;
16266        };
16267        let snapshot = self.snapshot(window, cx);
16268        if snapshot.intersects_fold(next_diagnostic.range.start) {
16269            self.unfold_ranges(
16270                std::slice::from_ref(&next_diagnostic.range),
16271                true,
16272                false,
16273                cx,
16274            );
16275        }
16276        self.change_selections(Default::default(), window, cx, |s| {
16277            s.select_ranges(vec![
16278                next_diagnostic.range.start..next_diagnostic.range.start,
16279            ])
16280        });
16281        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
16282        self.refresh_edit_prediction(false, true, window, cx);
16283    }
16284
16285    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
16286        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16287        let snapshot = self.snapshot(window, cx);
16288        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
16289        self.go_to_hunk_before_or_after_position(
16290            &snapshot,
16291            selection.head(),
16292            Direction::Next,
16293            window,
16294            cx,
16295        );
16296    }
16297
16298    pub fn go_to_hunk_before_or_after_position(
16299        &mut self,
16300        snapshot: &EditorSnapshot,
16301        position: Point,
16302        direction: Direction,
16303        window: &mut Window,
16304        cx: &mut Context<Editor>,
16305    ) {
16306        let row = if direction == Direction::Next {
16307            self.hunk_after_position(snapshot, position)
16308                .map(|hunk| hunk.row_range.start)
16309        } else {
16310            self.hunk_before_position(snapshot, position)
16311        };
16312
16313        if let Some(row) = row {
16314            let destination = Point::new(row.0, 0);
16315            let autoscroll = Autoscroll::center();
16316
16317            self.unfold_ranges(&[destination..destination], false, false, cx);
16318            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16319                s.select_ranges([destination..destination]);
16320            });
16321        }
16322    }
16323
16324    fn hunk_after_position(
16325        &mut self,
16326        snapshot: &EditorSnapshot,
16327        position: Point,
16328    ) -> Option<MultiBufferDiffHunk> {
16329        snapshot
16330            .buffer_snapshot()
16331            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
16332            .find(|hunk| hunk.row_range.start.0 > position.row)
16333            .or_else(|| {
16334                snapshot
16335                    .buffer_snapshot()
16336                    .diff_hunks_in_range(Point::zero()..position)
16337                    .find(|hunk| hunk.row_range.end.0 < position.row)
16338            })
16339    }
16340
16341    fn go_to_prev_hunk(
16342        &mut self,
16343        _: &GoToPreviousHunk,
16344        window: &mut Window,
16345        cx: &mut Context<Self>,
16346    ) {
16347        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16348        let snapshot = self.snapshot(window, cx);
16349        let selection = self.selections.newest::<Point>(&snapshot.display_snapshot);
16350        self.go_to_hunk_before_or_after_position(
16351            &snapshot,
16352            selection.head(),
16353            Direction::Prev,
16354            window,
16355            cx,
16356        );
16357    }
16358
16359    fn hunk_before_position(
16360        &mut self,
16361        snapshot: &EditorSnapshot,
16362        position: Point,
16363    ) -> Option<MultiBufferRow> {
16364        snapshot
16365            .buffer_snapshot()
16366            .diff_hunk_before(position)
16367            .or_else(|| snapshot.buffer_snapshot().diff_hunk_before(Point::MAX))
16368    }
16369
16370    fn go_to_next_change(
16371        &mut self,
16372        _: &GoToNextChange,
16373        window: &mut Window,
16374        cx: &mut Context<Self>,
16375    ) {
16376        if let Some(selections) = self
16377            .change_list
16378            .next_change(1, Direction::Next)
16379            .map(|s| s.to_vec())
16380        {
16381            self.change_selections(Default::default(), window, cx, |s| {
16382                let map = s.display_snapshot();
16383                s.select_display_ranges(selections.iter().map(|a| {
16384                    let point = a.to_display_point(&map);
16385                    point..point
16386                }))
16387            })
16388        }
16389    }
16390
16391    fn go_to_previous_change(
16392        &mut self,
16393        _: &GoToPreviousChange,
16394        window: &mut Window,
16395        cx: &mut Context<Self>,
16396    ) {
16397        if let Some(selections) = self
16398            .change_list
16399            .next_change(1, Direction::Prev)
16400            .map(|s| s.to_vec())
16401        {
16402            self.change_selections(Default::default(), window, cx, |s| {
16403                let map = s.display_snapshot();
16404                s.select_display_ranges(selections.iter().map(|a| {
16405                    let point = a.to_display_point(&map);
16406                    point..point
16407                }))
16408            })
16409        }
16410    }
16411
16412    pub fn go_to_next_document_highlight(
16413        &mut self,
16414        _: &GoToNextDocumentHighlight,
16415        window: &mut Window,
16416        cx: &mut Context<Self>,
16417    ) {
16418        self.go_to_document_highlight_before_or_after_position(Direction::Next, window, cx);
16419    }
16420
16421    pub fn go_to_prev_document_highlight(
16422        &mut self,
16423        _: &GoToPreviousDocumentHighlight,
16424        window: &mut Window,
16425        cx: &mut Context<Self>,
16426    ) {
16427        self.go_to_document_highlight_before_or_after_position(Direction::Prev, window, cx);
16428    }
16429
16430    pub fn go_to_document_highlight_before_or_after_position(
16431        &mut self,
16432        direction: Direction,
16433        window: &mut Window,
16434        cx: &mut Context<Editor>,
16435    ) {
16436        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16437        let snapshot = self.snapshot(window, cx);
16438        let buffer = &snapshot.buffer_snapshot();
16439        let position = self
16440            .selections
16441            .newest::<Point>(&snapshot.display_snapshot)
16442            .head();
16443        let anchor_position = buffer.anchor_after(position);
16444
16445        // Get all document highlights (both read and write)
16446        let mut all_highlights = Vec::new();
16447
16448        if let Some((_, read_highlights)) = self
16449            .background_highlights
16450            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
16451        {
16452            all_highlights.extend(read_highlights.iter());
16453        }
16454
16455        if let Some((_, write_highlights)) = self
16456            .background_highlights
16457            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
16458        {
16459            all_highlights.extend(write_highlights.iter());
16460        }
16461
16462        if all_highlights.is_empty() {
16463            return;
16464        }
16465
16466        // Sort highlights by position
16467        all_highlights.sort_by(|a, b| a.start.cmp(&b.start, buffer));
16468
16469        let target_highlight = match direction {
16470            Direction::Next => {
16471                // Find the first highlight after the current position
16472                all_highlights
16473                    .iter()
16474                    .find(|highlight| highlight.start.cmp(&anchor_position, buffer).is_gt())
16475            }
16476            Direction::Prev => {
16477                // Find the last highlight before the current position
16478                all_highlights
16479                    .iter()
16480                    .rev()
16481                    .find(|highlight| highlight.end.cmp(&anchor_position, buffer).is_lt())
16482            }
16483        };
16484
16485        if let Some(highlight) = target_highlight {
16486            let destination = highlight.start.to_point(buffer);
16487            let autoscroll = Autoscroll::center();
16488
16489            self.unfold_ranges(&[destination..destination], false, false, cx);
16490            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16491                s.select_ranges([destination..destination]);
16492            });
16493        }
16494    }
16495
16496    fn go_to_line<T: 'static>(
16497        &mut self,
16498        position: Anchor,
16499        highlight_color: Option<Hsla>,
16500        window: &mut Window,
16501        cx: &mut Context<Self>,
16502    ) {
16503        let snapshot = self.snapshot(window, cx).display_snapshot;
16504        let position = position.to_point(&snapshot.buffer_snapshot());
16505        let start = snapshot
16506            .buffer_snapshot()
16507            .clip_point(Point::new(position.row, 0), Bias::Left);
16508        let end = start + Point::new(1, 0);
16509        let start = snapshot.buffer_snapshot().anchor_before(start);
16510        let end = snapshot.buffer_snapshot().anchor_before(end);
16511
16512        self.highlight_rows::<T>(
16513            start..end,
16514            highlight_color
16515                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
16516            Default::default(),
16517            cx,
16518        );
16519
16520        if self.buffer.read(cx).is_singleton() {
16521            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
16522        }
16523    }
16524
16525    pub fn go_to_definition(
16526        &mut self,
16527        _: &GoToDefinition,
16528        window: &mut Window,
16529        cx: &mut Context<Self>,
16530    ) -> Task<Result<Navigated>> {
16531        let definition =
16532            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
16533        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
16534        cx.spawn_in(window, async move |editor, cx| {
16535            if definition.await? == Navigated::Yes {
16536                return Ok(Navigated::Yes);
16537            }
16538            match fallback_strategy {
16539                GoToDefinitionFallback::None => Ok(Navigated::No),
16540                GoToDefinitionFallback::FindAllReferences => {
16541                    match editor.update_in(cx, |editor, window, cx| {
16542                        editor.find_all_references(&FindAllReferences, window, cx)
16543                    })? {
16544                        Some(references) => references.await,
16545                        None => Ok(Navigated::No),
16546                    }
16547                }
16548            }
16549        })
16550    }
16551
16552    pub fn go_to_declaration(
16553        &mut self,
16554        _: &GoToDeclaration,
16555        window: &mut Window,
16556        cx: &mut Context<Self>,
16557    ) -> Task<Result<Navigated>> {
16558        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
16559    }
16560
16561    pub fn go_to_declaration_split(
16562        &mut self,
16563        _: &GoToDeclaration,
16564        window: &mut Window,
16565        cx: &mut Context<Self>,
16566    ) -> Task<Result<Navigated>> {
16567        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
16568    }
16569
16570    pub fn go_to_implementation(
16571        &mut self,
16572        _: &GoToImplementation,
16573        window: &mut Window,
16574        cx: &mut Context<Self>,
16575    ) -> Task<Result<Navigated>> {
16576        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
16577    }
16578
16579    pub fn go_to_implementation_split(
16580        &mut self,
16581        _: &GoToImplementationSplit,
16582        window: &mut Window,
16583        cx: &mut Context<Self>,
16584    ) -> Task<Result<Navigated>> {
16585        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
16586    }
16587
16588    pub fn go_to_type_definition(
16589        &mut self,
16590        _: &GoToTypeDefinition,
16591        window: &mut Window,
16592        cx: &mut Context<Self>,
16593    ) -> Task<Result<Navigated>> {
16594        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
16595    }
16596
16597    pub fn go_to_definition_split(
16598        &mut self,
16599        _: &GoToDefinitionSplit,
16600        window: &mut Window,
16601        cx: &mut Context<Self>,
16602    ) -> Task<Result<Navigated>> {
16603        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
16604    }
16605
16606    pub fn go_to_type_definition_split(
16607        &mut self,
16608        _: &GoToTypeDefinitionSplit,
16609        window: &mut Window,
16610        cx: &mut Context<Self>,
16611    ) -> Task<Result<Navigated>> {
16612        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
16613    }
16614
16615    fn go_to_definition_of_kind(
16616        &mut self,
16617        kind: GotoDefinitionKind,
16618        split: bool,
16619        window: &mut Window,
16620        cx: &mut Context<Self>,
16621    ) -> Task<Result<Navigated>> {
16622        let Some(provider) = self.semantics_provider.clone() else {
16623            return Task::ready(Ok(Navigated::No));
16624        };
16625        let head = self
16626            .selections
16627            .newest::<usize>(&self.display_snapshot(cx))
16628            .head();
16629        let buffer = self.buffer.read(cx);
16630        let Some((buffer, head)) = buffer.text_anchor_for_position(head, cx) else {
16631            return Task::ready(Ok(Navigated::No));
16632        };
16633        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
16634            return Task::ready(Ok(Navigated::No));
16635        };
16636
16637        cx.spawn_in(window, async move |editor, cx| {
16638            let Some(definitions) = definitions.await? else {
16639                return Ok(Navigated::No);
16640            };
16641            let navigated = editor
16642                .update_in(cx, |editor, window, cx| {
16643                    editor.navigate_to_hover_links(
16644                        Some(kind),
16645                        definitions
16646                            .into_iter()
16647                            .filter(|location| {
16648                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
16649                            })
16650                            .map(HoverLink::Text)
16651                            .collect::<Vec<_>>(),
16652                        split,
16653                        window,
16654                        cx,
16655                    )
16656                })?
16657                .await?;
16658            anyhow::Ok(navigated)
16659        })
16660    }
16661
16662    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
16663        let selection = self.selections.newest_anchor();
16664        let head = selection.head();
16665        let tail = selection.tail();
16666
16667        let Some((buffer, start_position)) =
16668            self.buffer.read(cx).text_anchor_for_position(head, cx)
16669        else {
16670            return;
16671        };
16672
16673        let end_position = if head != tail {
16674            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
16675                return;
16676            };
16677            Some(pos)
16678        } else {
16679            None
16680        };
16681
16682        let url_finder = cx.spawn_in(window, async move |_editor, cx| {
16683            let url = if let Some(end_pos) = end_position {
16684                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
16685            } else {
16686                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
16687            };
16688
16689            if let Some(url) = url {
16690                cx.update(|window, cx| {
16691                    if parse_zed_link(&url, cx).is_some() {
16692                        window.dispatch_action(Box::new(zed_actions::OpenZedUrl { url }), cx);
16693                    } else {
16694                        cx.open_url(&url);
16695                    }
16696                })?;
16697            }
16698
16699            anyhow::Ok(())
16700        });
16701
16702        url_finder.detach();
16703    }
16704
16705    pub fn open_selected_filename(
16706        &mut self,
16707        _: &OpenSelectedFilename,
16708        window: &mut Window,
16709        cx: &mut Context<Self>,
16710    ) {
16711        let Some(workspace) = self.workspace() else {
16712            return;
16713        };
16714
16715        let position = self.selections.newest_anchor().head();
16716
16717        let Some((buffer, buffer_position)) =
16718            self.buffer.read(cx).text_anchor_for_position(position, cx)
16719        else {
16720            return;
16721        };
16722
16723        let project = self.project.clone();
16724
16725        cx.spawn_in(window, async move |_, cx| {
16726            let result = find_file(&buffer, project, buffer_position, cx).await;
16727
16728            if let Some((_, path)) = result {
16729                workspace
16730                    .update_in(cx, |workspace, window, cx| {
16731                        workspace.open_resolved_path(path, window, cx)
16732                    })?
16733                    .await?;
16734            }
16735            anyhow::Ok(())
16736        })
16737        .detach();
16738    }
16739
16740    pub(crate) fn navigate_to_hover_links(
16741        &mut self,
16742        kind: Option<GotoDefinitionKind>,
16743        definitions: Vec<HoverLink>,
16744        split: bool,
16745        window: &mut Window,
16746        cx: &mut Context<Editor>,
16747    ) -> Task<Result<Navigated>> {
16748        // Separate out url and file links, we can only handle one of them at most or an arbitrary number of locations
16749        let mut first_url_or_file = None;
16750        let definitions: Vec<_> = definitions
16751            .into_iter()
16752            .filter_map(|def| match def {
16753                HoverLink::Text(link) => Some(Task::ready(anyhow::Ok(Some(link.target)))),
16754                HoverLink::InlayHint(lsp_location, server_id) => {
16755                    let computation =
16756                        self.compute_target_location(lsp_location, server_id, window, cx);
16757                    Some(cx.background_spawn(computation))
16758                }
16759                HoverLink::Url(url) => {
16760                    first_url_or_file = Some(Either::Left(url));
16761                    None
16762                }
16763                HoverLink::File(path) => {
16764                    first_url_or_file = Some(Either::Right(path));
16765                    None
16766                }
16767            })
16768            .collect();
16769
16770        let workspace = self.workspace();
16771
16772        cx.spawn_in(window, async move |editor, cx| {
16773            let locations: Vec<Location> = future::join_all(definitions)
16774                .await
16775                .into_iter()
16776                .filter_map(|location| location.transpose())
16777                .collect::<Result<_>>()
16778                .context("location tasks")?;
16779            let mut locations = cx.update(|_, cx| {
16780                locations
16781                    .into_iter()
16782                    .map(|location| {
16783                        let buffer = location.buffer.read(cx);
16784                        (location.buffer, location.range.to_point(buffer))
16785                    })
16786                    .into_group_map()
16787            })?;
16788            let mut num_locations = 0;
16789            for ranges in locations.values_mut() {
16790                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
16791                ranges.dedup();
16792                num_locations += ranges.len();
16793            }
16794
16795            if num_locations > 1 {
16796                let Some(workspace) = workspace else {
16797                    return Ok(Navigated::No);
16798                };
16799
16800                let tab_kind = match kind {
16801                    Some(GotoDefinitionKind::Implementation) => "Implementations",
16802                    Some(GotoDefinitionKind::Symbol) | None => "Definitions",
16803                    Some(GotoDefinitionKind::Declaration) => "Declarations",
16804                    Some(GotoDefinitionKind::Type) => "Types",
16805                };
16806                let title = editor
16807                    .update_in(cx, |_, _, cx| {
16808                        let target = locations
16809                            .iter()
16810                            .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
16811                            .map(|(buffer, location)| {
16812                                buffer
16813                                    .read(cx)
16814                                    .text_for_range(location.clone())
16815                                    .collect::<String>()
16816                            })
16817                            .filter(|text| !text.contains('\n'))
16818                            .unique()
16819                            .take(3)
16820                            .join(", ");
16821                        if target.is_empty() {
16822                            tab_kind.to_owned()
16823                        } else {
16824                            format!("{tab_kind} for {target}")
16825                        }
16826                    })
16827                    .context("buffer title")?;
16828
16829                let opened = workspace
16830                    .update_in(cx, |workspace, window, cx| {
16831                        Self::open_locations_in_multibuffer(
16832                            workspace,
16833                            locations,
16834                            title,
16835                            split,
16836                            MultibufferSelectionMode::First,
16837                            window,
16838                            cx,
16839                        )
16840                    })
16841                    .is_ok();
16842
16843                anyhow::Ok(Navigated::from_bool(opened))
16844            } else if num_locations == 0 {
16845                // If there is one url or file, open it directly
16846                match first_url_or_file {
16847                    Some(Either::Left(url)) => {
16848                        cx.update(|_, cx| cx.open_url(&url))?;
16849                        Ok(Navigated::Yes)
16850                    }
16851                    Some(Either::Right(path)) => {
16852                        let Some(workspace) = workspace else {
16853                            return Ok(Navigated::No);
16854                        };
16855
16856                        workspace
16857                            .update_in(cx, |workspace, window, cx| {
16858                                workspace.open_resolved_path(path, window, cx)
16859                            })?
16860                            .await?;
16861                        Ok(Navigated::Yes)
16862                    }
16863                    None => Ok(Navigated::No),
16864                }
16865            } else {
16866                let Some(workspace) = workspace else {
16867                    return Ok(Navigated::No);
16868                };
16869
16870                let (target_buffer, target_ranges) = locations.into_iter().next().unwrap();
16871                let target_range = target_ranges.first().unwrap().clone();
16872
16873                editor.update_in(cx, |editor, window, cx| {
16874                    let range = target_range.to_point(target_buffer.read(cx));
16875                    let range = editor.range_for_match(&range, false);
16876                    let range = collapse_multiline_range(range);
16877
16878                    if !split
16879                        && Some(&target_buffer) == editor.buffer.read(cx).as_singleton().as_ref()
16880                    {
16881                        editor.go_to_singleton_buffer_range(range, window, cx);
16882                    } else {
16883                        let pane = workspace.read(cx).active_pane().clone();
16884                        window.defer(cx, move |window, cx| {
16885                            let target_editor: Entity<Self> =
16886                                workspace.update(cx, |workspace, cx| {
16887                                    let pane = if split {
16888                                        workspace.adjacent_pane(window, cx)
16889                                    } else {
16890                                        workspace.active_pane().clone()
16891                                    };
16892
16893                                    workspace.open_project_item(
16894                                        pane,
16895                                        target_buffer.clone(),
16896                                        true,
16897                                        true,
16898                                        window,
16899                                        cx,
16900                                    )
16901                                });
16902                            target_editor.update(cx, |target_editor, cx| {
16903                                // When selecting a definition in a different buffer, disable the nav history
16904                                // to avoid creating a history entry at the previous cursor location.
16905                                pane.update(cx, |pane, _| pane.disable_history());
16906                                target_editor.go_to_singleton_buffer_range(range, window, cx);
16907                                pane.update(cx, |pane, _| pane.enable_history());
16908                            });
16909                        });
16910                    }
16911                    Navigated::Yes
16912                })
16913            }
16914        })
16915    }
16916
16917    fn compute_target_location(
16918        &self,
16919        lsp_location: lsp::Location,
16920        server_id: LanguageServerId,
16921        window: &mut Window,
16922        cx: &mut Context<Self>,
16923    ) -> Task<anyhow::Result<Option<Location>>> {
16924        let Some(project) = self.project.clone() else {
16925            return Task::ready(Ok(None));
16926        };
16927
16928        cx.spawn_in(window, async move |editor, cx| {
16929            let location_task = editor.update(cx, |_, cx| {
16930                project.update(cx, |project, cx| {
16931                    project.open_local_buffer_via_lsp(lsp_location.uri.clone(), server_id, cx)
16932                })
16933            })?;
16934            let location = Some({
16935                let target_buffer_handle = location_task.await.context("open local buffer")?;
16936                let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
16937                    let target_start = target_buffer
16938                        .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
16939                    let target_end = target_buffer
16940                        .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
16941                    target_buffer.anchor_after(target_start)
16942                        ..target_buffer.anchor_before(target_end)
16943                })?;
16944                Location {
16945                    buffer: target_buffer_handle,
16946                    range,
16947                }
16948            });
16949            Ok(location)
16950        })
16951    }
16952
16953    fn go_to_next_reference(
16954        &mut self,
16955        _: &GoToNextReference,
16956        window: &mut Window,
16957        cx: &mut Context<Self>,
16958    ) {
16959        let task = self.go_to_reference_before_or_after_position(Direction::Next, 1, window, cx);
16960        if let Some(task) = task {
16961            task.detach();
16962        };
16963    }
16964
16965    fn go_to_prev_reference(
16966        &mut self,
16967        _: &GoToPreviousReference,
16968        window: &mut Window,
16969        cx: &mut Context<Self>,
16970    ) {
16971        let task = self.go_to_reference_before_or_after_position(Direction::Prev, 1, window, cx);
16972        if let Some(task) = task {
16973            task.detach();
16974        };
16975    }
16976
16977    pub fn go_to_reference_before_or_after_position(
16978        &mut self,
16979        direction: Direction,
16980        count: usize,
16981        window: &mut Window,
16982        cx: &mut Context<Self>,
16983    ) -> Option<Task<Result<()>>> {
16984        let selection = self.selections.newest_anchor();
16985        let head = selection.head();
16986
16987        let multi_buffer = self.buffer.read(cx);
16988
16989        let (buffer, text_head) = multi_buffer.text_anchor_for_position(head, cx)?;
16990        let workspace = self.workspace()?;
16991        let project = workspace.read(cx).project().clone();
16992        let references =
16993            project.update(cx, |project, cx| project.references(&buffer, text_head, cx));
16994        Some(cx.spawn_in(window, async move |editor, cx| -> Result<()> {
16995            let Some(locations) = references.await? else {
16996                return Ok(());
16997            };
16998
16999            if locations.is_empty() {
17000                // totally normal - the cursor may be on something which is not
17001                // a symbol (e.g. a keyword)
17002                log::info!("no references found under cursor");
17003                return Ok(());
17004            }
17005
17006            let multi_buffer = editor.read_with(cx, |editor, _| editor.buffer().clone())?;
17007
17008            let multi_buffer_snapshot =
17009                multi_buffer.read_with(cx, |multi_buffer, cx| multi_buffer.snapshot(cx))?;
17010
17011            let (locations, current_location_index) =
17012                multi_buffer.update(cx, |multi_buffer, cx| {
17013                    let mut locations = locations
17014                        .into_iter()
17015                        .filter_map(|loc| {
17016                            let start = multi_buffer.buffer_anchor_to_anchor(
17017                                &loc.buffer,
17018                                loc.range.start,
17019                                cx,
17020                            )?;
17021                            let end = multi_buffer.buffer_anchor_to_anchor(
17022                                &loc.buffer,
17023                                loc.range.end,
17024                                cx,
17025                            )?;
17026                            Some(start..end)
17027                        })
17028                        .collect::<Vec<_>>();
17029
17030                    // There is an O(n) implementation, but given this list will be
17031                    // small (usually <100 items), the extra O(log(n)) factor isn't
17032                    // worth the (surprisingly large amount of) extra complexity.
17033                    locations
17034                        .sort_unstable_by(|l, r| l.start.cmp(&r.start, &multi_buffer_snapshot));
17035
17036                    let head_offset = head.to_offset(&multi_buffer_snapshot);
17037
17038                    let current_location_index = locations.iter().position(|loc| {
17039                        loc.start.to_offset(&multi_buffer_snapshot) <= head_offset
17040                            && loc.end.to_offset(&multi_buffer_snapshot) >= head_offset
17041                    });
17042
17043                    (locations, current_location_index)
17044                })?;
17045
17046            let Some(current_location_index) = current_location_index else {
17047                // This indicates something has gone wrong, because we already
17048                // handle the "no references" case above
17049                log::error!(
17050                    "failed to find current reference under cursor. Total references: {}",
17051                    locations.len()
17052                );
17053                return Ok(());
17054            };
17055
17056            let destination_location_index = match direction {
17057                Direction::Next => (current_location_index + count) % locations.len(),
17058                Direction::Prev => {
17059                    (current_location_index + locations.len() - count % locations.len())
17060                        % locations.len()
17061                }
17062            };
17063
17064            // TODO(cameron): is this needed?
17065            // the thinking is to avoid "jumping to the current location" (avoid
17066            // polluting "jumplist" in vim terms)
17067            if current_location_index == destination_location_index {
17068                return Ok(());
17069            }
17070
17071            let Range { start, end } = locations[destination_location_index];
17072
17073            editor.update_in(cx, |editor, window, cx| {
17074                let effects = SelectionEffects::default();
17075
17076                editor.unfold_ranges(&[start..end], false, false, cx);
17077                editor.change_selections(effects, window, cx, |s| {
17078                    s.select_ranges([start..start]);
17079                });
17080            })?;
17081
17082            Ok(())
17083        }))
17084    }
17085
17086    pub fn find_all_references(
17087        &mut self,
17088        _: &FindAllReferences,
17089        window: &mut Window,
17090        cx: &mut Context<Self>,
17091    ) -> Option<Task<Result<Navigated>>> {
17092        let selection = self.selections.newest::<usize>(&self.display_snapshot(cx));
17093        let multi_buffer = self.buffer.read(cx);
17094        let head = selection.head();
17095
17096        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
17097        let head_anchor = multi_buffer_snapshot.anchor_at(
17098            head,
17099            if head < selection.tail() {
17100                Bias::Right
17101            } else {
17102                Bias::Left
17103            },
17104        );
17105
17106        match self
17107            .find_all_references_task_sources
17108            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
17109        {
17110            Ok(_) => {
17111                log::info!(
17112                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
17113                );
17114                return None;
17115            }
17116            Err(i) => {
17117                self.find_all_references_task_sources.insert(i, head_anchor);
17118            }
17119        }
17120
17121        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
17122        let workspace = self.workspace()?;
17123        let project = workspace.read(cx).project().clone();
17124        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
17125        Some(cx.spawn_in(window, async move |editor, cx| {
17126            let _cleanup = cx.on_drop(&editor, move |editor, _| {
17127                if let Ok(i) = editor
17128                    .find_all_references_task_sources
17129                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
17130                {
17131                    editor.find_all_references_task_sources.remove(i);
17132                }
17133            });
17134
17135            let Some(locations) = references.await? else {
17136                return anyhow::Ok(Navigated::No);
17137            };
17138            let mut locations = cx.update(|_, cx| {
17139                locations
17140                    .into_iter()
17141                    .map(|location| {
17142                        let buffer = location.buffer.read(cx);
17143                        (location.buffer, location.range.to_point(buffer))
17144                    })
17145                    .into_group_map()
17146            })?;
17147            if locations.is_empty() {
17148                return anyhow::Ok(Navigated::No);
17149            }
17150            for ranges in locations.values_mut() {
17151                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
17152                ranges.dedup();
17153            }
17154
17155            workspace.update_in(cx, |workspace, window, cx| {
17156                let target = locations
17157                    .iter()
17158                    .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
17159                    .map(|(buffer, location)| {
17160                        buffer
17161                            .read(cx)
17162                            .text_for_range(location.clone())
17163                            .collect::<String>()
17164                    })
17165                    .filter(|text| !text.contains('\n'))
17166                    .unique()
17167                    .take(3)
17168                    .join(", ");
17169                let title = if target.is_empty() {
17170                    "References".to_owned()
17171                } else {
17172                    format!("References to {target}")
17173                };
17174                Self::open_locations_in_multibuffer(
17175                    workspace,
17176                    locations,
17177                    title,
17178                    false,
17179                    MultibufferSelectionMode::First,
17180                    window,
17181                    cx,
17182                );
17183                Navigated::Yes
17184            })
17185        }))
17186    }
17187
17188    /// Opens a multibuffer with the given project locations in it
17189    pub fn open_locations_in_multibuffer(
17190        workspace: &mut Workspace,
17191        locations: std::collections::HashMap<Entity<Buffer>, Vec<Range<Point>>>,
17192        title: String,
17193        split: bool,
17194        multibuffer_selection_mode: MultibufferSelectionMode,
17195        window: &mut Window,
17196        cx: &mut Context<Workspace>,
17197    ) {
17198        if locations.is_empty() {
17199            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
17200            return;
17201        }
17202
17203        let capability = workspace.project().read(cx).capability();
17204        let mut ranges = <Vec<Range<Anchor>>>::new();
17205
17206        // a key to find existing multibuffer editors with the same set of locations
17207        // to prevent us from opening more and more multibuffer tabs for searches and the like
17208        let mut key = (title.clone(), vec![]);
17209        let excerpt_buffer = cx.new(|cx| {
17210            let key = &mut key.1;
17211            let mut multibuffer = MultiBuffer::new(capability);
17212            for (buffer, mut ranges_for_buffer) in locations {
17213                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
17214                key.push((buffer.read(cx).remote_id(), ranges_for_buffer.clone()));
17215                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
17216                    PathKey::for_buffer(&buffer, cx),
17217                    buffer.clone(),
17218                    ranges_for_buffer,
17219                    multibuffer_context_lines(cx),
17220                    cx,
17221                );
17222                ranges.extend(new_ranges)
17223            }
17224
17225            multibuffer.with_title(title)
17226        });
17227        let existing = workspace.active_pane().update(cx, |pane, cx| {
17228            pane.items()
17229                .filter_map(|item| item.downcast::<Editor>())
17230                .find(|editor| {
17231                    editor
17232                        .read(cx)
17233                        .lookup_key
17234                        .as_ref()
17235                        .and_then(|it| {
17236                            it.downcast_ref::<(String, Vec<(BufferId, Vec<Range<Point>>)>)>()
17237                        })
17238                        .is_some_and(|it| *it == key)
17239                })
17240        });
17241        let editor = existing.unwrap_or_else(|| {
17242            cx.new(|cx| {
17243                let mut editor = Editor::for_multibuffer(
17244                    excerpt_buffer,
17245                    Some(workspace.project().clone()),
17246                    window,
17247                    cx,
17248                );
17249                editor.lookup_key = Some(Box::new(key));
17250                editor
17251            })
17252        });
17253        editor.update(cx, |editor, cx| match multibuffer_selection_mode {
17254            MultibufferSelectionMode::First => {
17255                if let Some(first_range) = ranges.first() {
17256                    editor.change_selections(
17257                        SelectionEffects::no_scroll(),
17258                        window,
17259                        cx,
17260                        |selections| {
17261                            selections.clear_disjoint();
17262                            selections.select_anchor_ranges(std::iter::once(first_range.clone()));
17263                        },
17264                    );
17265                }
17266                editor.highlight_background::<Self>(
17267                    &ranges,
17268                    |theme| theme.colors().editor_highlighted_line_background,
17269                    cx,
17270                );
17271            }
17272            MultibufferSelectionMode::All => {
17273                editor.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
17274                    selections.clear_disjoint();
17275                    selections.select_anchor_ranges(ranges);
17276                });
17277            }
17278        });
17279
17280        let item = Box::new(editor);
17281        let item_id = item.item_id();
17282
17283        if split {
17284            let pane = workspace.adjacent_pane(window, cx);
17285            workspace.add_item(pane, item, None, true, true, window, cx);
17286        } else if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
17287            let (preview_item_id, preview_item_idx) =
17288                workspace.active_pane().read_with(cx, |pane, _| {
17289                    (pane.preview_item_id(), pane.preview_item_idx())
17290                });
17291
17292            workspace.add_item_to_active_pane(item, preview_item_idx, true, window, cx);
17293
17294            if let Some(preview_item_id) = preview_item_id {
17295                workspace.active_pane().update(cx, |pane, cx| {
17296                    pane.remove_item(preview_item_id, false, false, window, cx);
17297                });
17298            }
17299        } else {
17300            workspace.add_item_to_active_pane(item, None, true, window, cx);
17301        }
17302        workspace.active_pane().update(cx, |pane, cx| {
17303            pane.set_preview_item_id(Some(item_id), cx);
17304        });
17305    }
17306
17307    pub fn rename(
17308        &mut self,
17309        _: &Rename,
17310        window: &mut Window,
17311        cx: &mut Context<Self>,
17312    ) -> Option<Task<Result<()>>> {
17313        use language::ToOffset as _;
17314
17315        let provider = self.semantics_provider.clone()?;
17316        let selection = self.selections.newest_anchor().clone();
17317        let (cursor_buffer, cursor_buffer_position) = self
17318            .buffer
17319            .read(cx)
17320            .text_anchor_for_position(selection.head(), cx)?;
17321        let (tail_buffer, cursor_buffer_position_end) = self
17322            .buffer
17323            .read(cx)
17324            .text_anchor_for_position(selection.tail(), cx)?;
17325        if tail_buffer != cursor_buffer {
17326            return None;
17327        }
17328
17329        let snapshot = cursor_buffer.read(cx).snapshot();
17330        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
17331        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
17332        let prepare_rename = provider
17333            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
17334            .unwrap_or_else(|| Task::ready(Ok(None)));
17335        drop(snapshot);
17336
17337        Some(cx.spawn_in(window, async move |this, cx| {
17338            let rename_range = if let Some(range) = prepare_rename.await? {
17339                Some(range)
17340            } else {
17341                this.update(cx, |this, cx| {
17342                    let buffer = this.buffer.read(cx).snapshot(cx);
17343                    let mut buffer_highlights = this
17344                        .document_highlights_for_position(selection.head(), &buffer)
17345                        .filter(|highlight| {
17346                            highlight.start.excerpt_id == selection.head().excerpt_id
17347                                && highlight.end.excerpt_id == selection.head().excerpt_id
17348                        });
17349                    buffer_highlights
17350                        .next()
17351                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
17352                })?
17353            };
17354            if let Some(rename_range) = rename_range {
17355                this.update_in(cx, |this, window, cx| {
17356                    let snapshot = cursor_buffer.read(cx).snapshot();
17357                    let rename_buffer_range = rename_range.to_offset(&snapshot);
17358                    let cursor_offset_in_rename_range =
17359                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
17360                    let cursor_offset_in_rename_range_end =
17361                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
17362
17363                    this.take_rename(false, window, cx);
17364                    let buffer = this.buffer.read(cx).read(cx);
17365                    let cursor_offset = selection.head().to_offset(&buffer);
17366                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
17367                    let rename_end = rename_start + rename_buffer_range.len();
17368                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
17369                    let mut old_highlight_id = None;
17370                    let old_name: Arc<str> = buffer
17371                        .chunks(rename_start..rename_end, true)
17372                        .map(|chunk| {
17373                            if old_highlight_id.is_none() {
17374                                old_highlight_id = chunk.syntax_highlight_id;
17375                            }
17376                            chunk.text
17377                        })
17378                        .collect::<String>()
17379                        .into();
17380
17381                    drop(buffer);
17382
17383                    // Position the selection in the rename editor so that it matches the current selection.
17384                    this.show_local_selections = false;
17385                    let rename_editor = cx.new(|cx| {
17386                        let mut editor = Editor::single_line(window, cx);
17387                        editor.buffer.update(cx, |buffer, cx| {
17388                            buffer.edit([(0..0, old_name.clone())], None, cx)
17389                        });
17390                        let rename_selection_range = match cursor_offset_in_rename_range
17391                            .cmp(&cursor_offset_in_rename_range_end)
17392                        {
17393                            Ordering::Equal => {
17394                                editor.select_all(&SelectAll, window, cx);
17395                                return editor;
17396                            }
17397                            Ordering::Less => {
17398                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
17399                            }
17400                            Ordering::Greater => {
17401                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
17402                            }
17403                        };
17404                        if rename_selection_range.end > old_name.len() {
17405                            editor.select_all(&SelectAll, window, cx);
17406                        } else {
17407                            editor.change_selections(Default::default(), window, cx, |s| {
17408                                s.select_ranges([rename_selection_range]);
17409                            });
17410                        }
17411                        editor
17412                    });
17413                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
17414                        if e == &EditorEvent::Focused {
17415                            cx.emit(EditorEvent::FocusedIn)
17416                        }
17417                    })
17418                    .detach();
17419
17420                    let write_highlights =
17421                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
17422                    let read_highlights =
17423                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
17424                    let ranges = write_highlights
17425                        .iter()
17426                        .flat_map(|(_, ranges)| ranges.iter())
17427                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
17428                        .cloned()
17429                        .collect();
17430
17431                    this.highlight_text::<Rename>(
17432                        ranges,
17433                        HighlightStyle {
17434                            fade_out: Some(0.6),
17435                            ..Default::default()
17436                        },
17437                        cx,
17438                    );
17439                    let rename_focus_handle = rename_editor.focus_handle(cx);
17440                    window.focus(&rename_focus_handle);
17441                    let block_id = this.insert_blocks(
17442                        [BlockProperties {
17443                            style: BlockStyle::Flex,
17444                            placement: BlockPlacement::Below(range.start),
17445                            height: Some(1),
17446                            render: Arc::new({
17447                                let rename_editor = rename_editor.clone();
17448                                move |cx: &mut BlockContext| {
17449                                    let mut text_style = cx.editor_style.text.clone();
17450                                    if let Some(highlight_style) = old_highlight_id
17451                                        .and_then(|h| h.style(&cx.editor_style.syntax))
17452                                    {
17453                                        text_style = text_style.highlight(highlight_style);
17454                                    }
17455                                    div()
17456                                        .block_mouse_except_scroll()
17457                                        .pl(cx.anchor_x)
17458                                        .child(EditorElement::new(
17459                                            &rename_editor,
17460                                            EditorStyle {
17461                                                background: cx.theme().system().transparent,
17462                                                local_player: cx.editor_style.local_player,
17463                                                text: text_style,
17464                                                scrollbar_width: cx.editor_style.scrollbar_width,
17465                                                syntax: cx.editor_style.syntax.clone(),
17466                                                status: cx.editor_style.status.clone(),
17467                                                inlay_hints_style: HighlightStyle {
17468                                                    font_weight: Some(FontWeight::BOLD),
17469                                                    ..make_inlay_hints_style(cx.app)
17470                                                },
17471                                                edit_prediction_styles: make_suggestion_styles(
17472                                                    cx.app,
17473                                                ),
17474                                                ..EditorStyle::default()
17475                                            },
17476                                        ))
17477                                        .into_any_element()
17478                                }
17479                            }),
17480                            priority: 0,
17481                        }],
17482                        Some(Autoscroll::fit()),
17483                        cx,
17484                    )[0];
17485                    this.pending_rename = Some(RenameState {
17486                        range,
17487                        old_name,
17488                        editor: rename_editor,
17489                        block_id,
17490                    });
17491                })?;
17492            }
17493
17494            Ok(())
17495        }))
17496    }
17497
17498    pub fn confirm_rename(
17499        &mut self,
17500        _: &ConfirmRename,
17501        window: &mut Window,
17502        cx: &mut Context<Self>,
17503    ) -> Option<Task<Result<()>>> {
17504        let rename = self.take_rename(false, window, cx)?;
17505        let workspace = self.workspace()?.downgrade();
17506        let (buffer, start) = self
17507            .buffer
17508            .read(cx)
17509            .text_anchor_for_position(rename.range.start, cx)?;
17510        let (end_buffer, _) = self
17511            .buffer
17512            .read(cx)
17513            .text_anchor_for_position(rename.range.end, cx)?;
17514        if buffer != end_buffer {
17515            return None;
17516        }
17517
17518        let old_name = rename.old_name;
17519        let new_name = rename.editor.read(cx).text(cx);
17520
17521        let rename = self.semantics_provider.as_ref()?.perform_rename(
17522            &buffer,
17523            start,
17524            new_name.clone(),
17525            cx,
17526        )?;
17527
17528        Some(cx.spawn_in(window, async move |editor, cx| {
17529            let project_transaction = rename.await?;
17530            Self::open_project_transaction(
17531                &editor,
17532                workspace,
17533                project_transaction,
17534                format!("Rename: {}{}", old_name, new_name),
17535                cx,
17536            )
17537            .await?;
17538
17539            editor.update(cx, |editor, cx| {
17540                editor.refresh_document_highlights(cx);
17541            })?;
17542            Ok(())
17543        }))
17544    }
17545
17546    fn take_rename(
17547        &mut self,
17548        moving_cursor: bool,
17549        window: &mut Window,
17550        cx: &mut Context<Self>,
17551    ) -> Option<RenameState> {
17552        let rename = self.pending_rename.take()?;
17553        if rename.editor.focus_handle(cx).is_focused(window) {
17554            window.focus(&self.focus_handle);
17555        }
17556
17557        self.remove_blocks(
17558            [rename.block_id].into_iter().collect(),
17559            Some(Autoscroll::fit()),
17560            cx,
17561        );
17562        self.clear_highlights::<Rename>(cx);
17563        self.show_local_selections = true;
17564
17565        if moving_cursor {
17566            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
17567                editor
17568                    .selections
17569                    .newest::<usize>(&editor.display_snapshot(cx))
17570                    .head()
17571            });
17572
17573            // Update the selection to match the position of the selection inside
17574            // the rename editor.
17575            let snapshot = self.buffer.read(cx).read(cx);
17576            let rename_range = rename.range.to_offset(&snapshot);
17577            let cursor_in_editor = snapshot
17578                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
17579                .min(rename_range.end);
17580            drop(snapshot);
17581
17582            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17583                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
17584            });
17585        } else {
17586            self.refresh_document_highlights(cx);
17587        }
17588
17589        Some(rename)
17590    }
17591
17592    pub fn pending_rename(&self) -> Option<&RenameState> {
17593        self.pending_rename.as_ref()
17594    }
17595
17596    fn format(
17597        &mut self,
17598        _: &Format,
17599        window: &mut Window,
17600        cx: &mut Context<Self>,
17601    ) -> Option<Task<Result<()>>> {
17602        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17603
17604        let project = match &self.project {
17605            Some(project) => project.clone(),
17606            None => return None,
17607        };
17608
17609        Some(self.perform_format(
17610            project,
17611            FormatTrigger::Manual,
17612            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
17613            window,
17614            cx,
17615        ))
17616    }
17617
17618    fn format_selections(
17619        &mut self,
17620        _: &FormatSelections,
17621        window: &mut Window,
17622        cx: &mut Context<Self>,
17623    ) -> Option<Task<Result<()>>> {
17624        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17625
17626        let project = match &self.project {
17627            Some(project) => project.clone(),
17628            None => return None,
17629        };
17630
17631        let ranges = self
17632            .selections
17633            .all_adjusted(&self.display_snapshot(cx))
17634            .into_iter()
17635            .map(|selection| selection.range())
17636            .collect_vec();
17637
17638        Some(self.perform_format(
17639            project,
17640            FormatTrigger::Manual,
17641            FormatTarget::Ranges(ranges),
17642            window,
17643            cx,
17644        ))
17645    }
17646
17647    fn perform_format(
17648        &mut self,
17649        project: Entity<Project>,
17650        trigger: FormatTrigger,
17651        target: FormatTarget,
17652        window: &mut Window,
17653        cx: &mut Context<Self>,
17654    ) -> Task<Result<()>> {
17655        let buffer = self.buffer.clone();
17656        let (buffers, target) = match target {
17657            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
17658            FormatTarget::Ranges(selection_ranges) => {
17659                let multi_buffer = buffer.read(cx);
17660                let snapshot = multi_buffer.read(cx);
17661                let mut buffers = HashSet::default();
17662                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
17663                    BTreeMap::new();
17664                for selection_range in selection_ranges {
17665                    for (buffer, buffer_range, _) in
17666                        snapshot.range_to_buffer_ranges(selection_range)
17667                    {
17668                        let buffer_id = buffer.remote_id();
17669                        let start = buffer.anchor_before(buffer_range.start);
17670                        let end = buffer.anchor_after(buffer_range.end);
17671                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
17672                        buffer_id_to_ranges
17673                            .entry(buffer_id)
17674                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
17675                            .or_insert_with(|| vec![start..end]);
17676                    }
17677                }
17678                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
17679            }
17680        };
17681
17682        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
17683        let selections_prev = transaction_id_prev
17684            .and_then(|transaction_id_prev| {
17685                // default to selections as they were after the last edit, if we have them,
17686                // instead of how they are now.
17687                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
17688                // will take you back to where you made the last edit, instead of staying where you scrolled
17689                self.selection_history
17690                    .transaction(transaction_id_prev)
17691                    .map(|t| t.0.clone())
17692            })
17693            .unwrap_or_else(|| self.selections.disjoint_anchors_arc());
17694
17695        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
17696        let format = project.update(cx, |project, cx| {
17697            project.format(buffers, target, true, trigger, cx)
17698        });
17699
17700        cx.spawn_in(window, async move |editor, cx| {
17701            let transaction = futures::select_biased! {
17702                transaction = format.log_err().fuse() => transaction,
17703                () = timeout => {
17704                    log::warn!("timed out waiting for formatting");
17705                    None
17706                }
17707            };
17708
17709            buffer
17710                .update(cx, |buffer, cx| {
17711                    if let Some(transaction) = transaction
17712                        && !buffer.is_singleton()
17713                    {
17714                        buffer.push_transaction(&transaction.0, cx);
17715                    }
17716                    cx.notify();
17717                })
17718                .ok();
17719
17720            if let Some(transaction_id_now) =
17721                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
17722            {
17723                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
17724                if has_new_transaction {
17725                    _ = editor.update(cx, |editor, _| {
17726                        editor
17727                            .selection_history
17728                            .insert_transaction(transaction_id_now, selections_prev);
17729                    });
17730                }
17731            }
17732
17733            Ok(())
17734        })
17735    }
17736
17737    fn organize_imports(
17738        &mut self,
17739        _: &OrganizeImports,
17740        window: &mut Window,
17741        cx: &mut Context<Self>,
17742    ) -> Option<Task<Result<()>>> {
17743        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17744        let project = match &self.project {
17745            Some(project) => project.clone(),
17746            None => return None,
17747        };
17748        Some(self.perform_code_action_kind(
17749            project,
17750            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
17751            window,
17752            cx,
17753        ))
17754    }
17755
17756    fn perform_code_action_kind(
17757        &mut self,
17758        project: Entity<Project>,
17759        kind: CodeActionKind,
17760        window: &mut Window,
17761        cx: &mut Context<Self>,
17762    ) -> Task<Result<()>> {
17763        let buffer = self.buffer.clone();
17764        let buffers = buffer.read(cx).all_buffers();
17765        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
17766        let apply_action = project.update(cx, |project, cx| {
17767            project.apply_code_action_kind(buffers, kind, true, cx)
17768        });
17769        cx.spawn_in(window, async move |_, cx| {
17770            let transaction = futures::select_biased! {
17771                () = timeout => {
17772                    log::warn!("timed out waiting for executing code action");
17773                    None
17774                }
17775                transaction = apply_action.log_err().fuse() => transaction,
17776            };
17777            buffer
17778                .update(cx, |buffer, cx| {
17779                    // check if we need this
17780                    if let Some(transaction) = transaction
17781                        && !buffer.is_singleton()
17782                    {
17783                        buffer.push_transaction(&transaction.0, cx);
17784                    }
17785                    cx.notify();
17786                })
17787                .ok();
17788            Ok(())
17789        })
17790    }
17791
17792    pub fn restart_language_server(
17793        &mut self,
17794        _: &RestartLanguageServer,
17795        _: &mut Window,
17796        cx: &mut Context<Self>,
17797    ) {
17798        if let Some(project) = self.project.clone() {
17799            self.buffer.update(cx, |multi_buffer, cx| {
17800                project.update(cx, |project, cx| {
17801                    project.restart_language_servers_for_buffers(
17802                        multi_buffer.all_buffers().into_iter().collect(),
17803                        HashSet::default(),
17804                        cx,
17805                    );
17806                });
17807            })
17808        }
17809    }
17810
17811    pub fn stop_language_server(
17812        &mut self,
17813        _: &StopLanguageServer,
17814        _: &mut Window,
17815        cx: &mut Context<Self>,
17816    ) {
17817        if let Some(project) = self.project.clone() {
17818            self.buffer.update(cx, |multi_buffer, cx| {
17819                project.update(cx, |project, cx| {
17820                    project.stop_language_servers_for_buffers(
17821                        multi_buffer.all_buffers().into_iter().collect(),
17822                        HashSet::default(),
17823                        cx,
17824                    );
17825                });
17826            });
17827            self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
17828        }
17829    }
17830
17831    fn cancel_language_server_work(
17832        workspace: &mut Workspace,
17833        _: &actions::CancelLanguageServerWork,
17834        _: &mut Window,
17835        cx: &mut Context<Workspace>,
17836    ) {
17837        let project = workspace.project();
17838        let buffers = workspace
17839            .active_item(cx)
17840            .and_then(|item| item.act_as::<Editor>(cx))
17841            .map_or(HashSet::default(), |editor| {
17842                editor.read(cx).buffer.read(cx).all_buffers()
17843            });
17844        project.update(cx, |project, cx| {
17845            project.cancel_language_server_work_for_buffers(buffers, cx);
17846        });
17847    }
17848
17849    fn show_character_palette(
17850        &mut self,
17851        _: &ShowCharacterPalette,
17852        window: &mut Window,
17853        _: &mut Context<Self>,
17854    ) {
17855        window.show_character_palette();
17856    }
17857
17858    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
17859        if !self.diagnostics_enabled() {
17860            return;
17861        }
17862
17863        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
17864            let buffer = self.buffer.read(cx).snapshot(cx);
17865            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
17866            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
17867            let is_valid = buffer
17868                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
17869                .any(|entry| {
17870                    entry.diagnostic.is_primary
17871                        && !entry.range.is_empty()
17872                        && entry.range.start == primary_range_start
17873                        && entry.diagnostic.message == active_diagnostics.active_message
17874                });
17875
17876            if !is_valid {
17877                self.dismiss_diagnostics(cx);
17878            }
17879        }
17880    }
17881
17882    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
17883        match &self.active_diagnostics {
17884            ActiveDiagnostic::Group(group) => Some(group),
17885            _ => None,
17886        }
17887    }
17888
17889    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
17890        if !self.diagnostics_enabled() {
17891            return;
17892        }
17893        self.dismiss_diagnostics(cx);
17894        self.active_diagnostics = ActiveDiagnostic::All;
17895    }
17896
17897    fn activate_diagnostics(
17898        &mut self,
17899        buffer_id: BufferId,
17900        diagnostic: DiagnosticEntryRef<'_, usize>,
17901        window: &mut Window,
17902        cx: &mut Context<Self>,
17903    ) {
17904        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
17905            return;
17906        }
17907        self.dismiss_diagnostics(cx);
17908        let snapshot = self.snapshot(window, cx);
17909        let buffer = self.buffer.read(cx).snapshot(cx);
17910        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
17911            return;
17912        };
17913
17914        let diagnostic_group = buffer
17915            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
17916            .collect::<Vec<_>>();
17917
17918        let blocks =
17919            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
17920
17921        let blocks = self.display_map.update(cx, |display_map, cx| {
17922            display_map.insert_blocks(blocks, cx).into_iter().collect()
17923        });
17924        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
17925            active_range: buffer.anchor_before(diagnostic.range.start)
17926                ..buffer.anchor_after(diagnostic.range.end),
17927            active_message: diagnostic.diagnostic.message.clone(),
17928            group_id: diagnostic.diagnostic.group_id,
17929            blocks,
17930        });
17931        cx.notify();
17932    }
17933
17934    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
17935        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
17936            return;
17937        };
17938
17939        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
17940        if let ActiveDiagnostic::Group(group) = prev {
17941            self.display_map.update(cx, |display_map, cx| {
17942                display_map.remove_blocks(group.blocks, cx);
17943            });
17944            cx.notify();
17945        }
17946    }
17947
17948    /// Disable inline diagnostics rendering for this editor.
17949    pub fn disable_inline_diagnostics(&mut self) {
17950        self.inline_diagnostics_enabled = false;
17951        self.inline_diagnostics_update = Task::ready(());
17952        self.inline_diagnostics.clear();
17953    }
17954
17955    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
17956        self.diagnostics_enabled = false;
17957        self.dismiss_diagnostics(cx);
17958        self.inline_diagnostics_update = Task::ready(());
17959        self.inline_diagnostics.clear();
17960    }
17961
17962    pub fn disable_word_completions(&mut self) {
17963        self.word_completions_enabled = false;
17964    }
17965
17966    pub fn diagnostics_enabled(&self) -> bool {
17967        self.diagnostics_enabled && self.mode.is_full()
17968    }
17969
17970    pub fn inline_diagnostics_enabled(&self) -> bool {
17971        self.inline_diagnostics_enabled && self.diagnostics_enabled()
17972    }
17973
17974    pub fn show_inline_diagnostics(&self) -> bool {
17975        self.show_inline_diagnostics
17976    }
17977
17978    pub fn toggle_inline_diagnostics(
17979        &mut self,
17980        _: &ToggleInlineDiagnostics,
17981        window: &mut Window,
17982        cx: &mut Context<Editor>,
17983    ) {
17984        self.show_inline_diagnostics = !self.show_inline_diagnostics;
17985        self.refresh_inline_diagnostics(false, window, cx);
17986    }
17987
17988    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
17989        self.diagnostics_max_severity = severity;
17990        self.display_map.update(cx, |display_map, _| {
17991            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
17992        });
17993    }
17994
17995    pub fn toggle_diagnostics(
17996        &mut self,
17997        _: &ToggleDiagnostics,
17998        window: &mut Window,
17999        cx: &mut Context<Editor>,
18000    ) {
18001        if !self.diagnostics_enabled() {
18002            return;
18003        }
18004
18005        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
18006            EditorSettings::get_global(cx)
18007                .diagnostics_max_severity
18008                .filter(|severity| severity != &DiagnosticSeverity::Off)
18009                .unwrap_or(DiagnosticSeverity::Hint)
18010        } else {
18011            DiagnosticSeverity::Off
18012        };
18013        self.set_max_diagnostics_severity(new_severity, cx);
18014        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
18015            self.active_diagnostics = ActiveDiagnostic::None;
18016            self.inline_diagnostics_update = Task::ready(());
18017            self.inline_diagnostics.clear();
18018        } else {
18019            self.refresh_inline_diagnostics(false, window, cx);
18020        }
18021
18022        cx.notify();
18023    }
18024
18025    pub fn toggle_minimap(
18026        &mut self,
18027        _: &ToggleMinimap,
18028        window: &mut Window,
18029        cx: &mut Context<Editor>,
18030    ) {
18031        if self.supports_minimap(cx) {
18032            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
18033        }
18034    }
18035
18036    fn refresh_inline_diagnostics(
18037        &mut self,
18038        debounce: bool,
18039        window: &mut Window,
18040        cx: &mut Context<Self>,
18041    ) {
18042        let max_severity = ProjectSettings::get_global(cx)
18043            .diagnostics
18044            .inline
18045            .max_severity
18046            .unwrap_or(self.diagnostics_max_severity);
18047
18048        if !self.inline_diagnostics_enabled()
18049            || !self.diagnostics_enabled()
18050            || !self.show_inline_diagnostics
18051            || max_severity == DiagnosticSeverity::Off
18052        {
18053            self.inline_diagnostics_update = Task::ready(());
18054            self.inline_diagnostics.clear();
18055            return;
18056        }
18057
18058        let debounce_ms = ProjectSettings::get_global(cx)
18059            .diagnostics
18060            .inline
18061            .update_debounce_ms;
18062        let debounce = if debounce && debounce_ms > 0 {
18063            Some(Duration::from_millis(debounce_ms))
18064        } else {
18065            None
18066        };
18067        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
18068            if let Some(debounce) = debounce {
18069                cx.background_executor().timer(debounce).await;
18070            }
18071            let Some(snapshot) = editor.upgrade().and_then(|editor| {
18072                editor
18073                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
18074                    .ok()
18075            }) else {
18076                return;
18077            };
18078
18079            let new_inline_diagnostics = cx
18080                .background_spawn(async move {
18081                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
18082                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
18083                        let message = diagnostic_entry
18084                            .diagnostic
18085                            .message
18086                            .split_once('\n')
18087                            .map(|(line, _)| line)
18088                            .map(SharedString::new)
18089                            .unwrap_or_else(|| {
18090                                SharedString::new(&*diagnostic_entry.diagnostic.message)
18091                            });
18092                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
18093                        let (Ok(i) | Err(i)) = inline_diagnostics
18094                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
18095                        inline_diagnostics.insert(
18096                            i,
18097                            (
18098                                start_anchor,
18099                                InlineDiagnostic {
18100                                    message,
18101                                    group_id: diagnostic_entry.diagnostic.group_id,
18102                                    start: diagnostic_entry.range.start.to_point(&snapshot),
18103                                    is_primary: diagnostic_entry.diagnostic.is_primary,
18104                                    severity: diagnostic_entry.diagnostic.severity,
18105                                },
18106                            ),
18107                        );
18108                    }
18109                    inline_diagnostics
18110                })
18111                .await;
18112
18113            editor
18114                .update(cx, |editor, cx| {
18115                    editor.inline_diagnostics = new_inline_diagnostics;
18116                    cx.notify();
18117                })
18118                .ok();
18119        });
18120    }
18121
18122    fn pull_diagnostics(
18123        &mut self,
18124        buffer_id: Option<BufferId>,
18125        window: &Window,
18126        cx: &mut Context<Self>,
18127    ) -> Option<()> {
18128        if self.ignore_lsp_data() || !self.diagnostics_enabled() {
18129            return None;
18130        }
18131        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
18132            .diagnostics
18133            .lsp_pull_diagnostics;
18134        if !pull_diagnostics_settings.enabled {
18135            return None;
18136        }
18137        let project = self.project()?.downgrade();
18138        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
18139        let mut buffers = self.buffer.read(cx).all_buffers();
18140        buffers.retain(|buffer| {
18141            let buffer_id_to_retain = buffer.read(cx).remote_id();
18142            buffer_id.is_none_or(|buffer_id| buffer_id == buffer_id_to_retain)
18143                && self.registered_buffers.contains_key(&buffer_id_to_retain)
18144        });
18145        if buffers.is_empty() {
18146            self.pull_diagnostics_task = Task::ready(());
18147            return None;
18148        }
18149
18150        self.pull_diagnostics_task = cx.spawn_in(window, async move |editor, cx| {
18151            cx.background_executor().timer(debounce).await;
18152
18153            let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
18154                buffers
18155                    .into_iter()
18156                    .filter_map(|buffer| {
18157                        project
18158                            .update(cx, |project, cx| {
18159                                project.lsp_store().update(cx, |lsp_store, cx| {
18160                                    lsp_store.pull_diagnostics_for_buffer(buffer, cx)
18161                                })
18162                            })
18163                            .ok()
18164                    })
18165                    .collect::<FuturesUnordered<_>>()
18166            }) else {
18167                return;
18168            };
18169
18170            while let Some(pull_task) = pull_diagnostics_tasks.next().await {
18171                match pull_task {
18172                    Ok(()) => {
18173                        if editor
18174                            .update_in(cx, |editor, window, cx| {
18175                                editor.update_diagnostics_state(window, cx);
18176                            })
18177                            .is_err()
18178                        {
18179                            return;
18180                        }
18181                    }
18182                    Err(e) => log::error!("Failed to update project diagnostics: {e:#}"),
18183                }
18184            }
18185        });
18186
18187        Some(())
18188    }
18189
18190    pub fn set_selections_from_remote(
18191        &mut self,
18192        selections: Vec<Selection<Anchor>>,
18193        pending_selection: Option<Selection<Anchor>>,
18194        window: &mut Window,
18195        cx: &mut Context<Self>,
18196    ) {
18197        let old_cursor_position = self.selections.newest_anchor().head();
18198        self.selections
18199            .change_with(&self.display_snapshot(cx), |s| {
18200                s.select_anchors(selections);
18201                if let Some(pending_selection) = pending_selection {
18202                    s.set_pending(pending_selection, SelectMode::Character);
18203                } else {
18204                    s.clear_pending();
18205                }
18206            });
18207        self.selections_did_change(
18208            false,
18209            &old_cursor_position,
18210            SelectionEffects::default(),
18211            window,
18212            cx,
18213        );
18214    }
18215
18216    pub fn transact(
18217        &mut self,
18218        window: &mut Window,
18219        cx: &mut Context<Self>,
18220        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
18221    ) -> Option<TransactionId> {
18222        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
18223            this.start_transaction_at(Instant::now(), window, cx);
18224            update(this, window, cx);
18225            this.end_transaction_at(Instant::now(), cx)
18226        })
18227    }
18228
18229    pub fn start_transaction_at(
18230        &mut self,
18231        now: Instant,
18232        window: &mut Window,
18233        cx: &mut Context<Self>,
18234    ) -> Option<TransactionId> {
18235        self.end_selection(window, cx);
18236        if let Some(tx_id) = self
18237            .buffer
18238            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
18239        {
18240            self.selection_history
18241                .insert_transaction(tx_id, self.selections.disjoint_anchors_arc());
18242            cx.emit(EditorEvent::TransactionBegun {
18243                transaction_id: tx_id,
18244            });
18245            Some(tx_id)
18246        } else {
18247            None
18248        }
18249    }
18250
18251    pub fn end_transaction_at(
18252        &mut self,
18253        now: Instant,
18254        cx: &mut Context<Self>,
18255    ) -> Option<TransactionId> {
18256        if let Some(transaction_id) = self
18257            .buffer
18258            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
18259        {
18260            if let Some((_, end_selections)) =
18261                self.selection_history.transaction_mut(transaction_id)
18262            {
18263                *end_selections = Some(self.selections.disjoint_anchors_arc());
18264            } else {
18265                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
18266            }
18267
18268            cx.emit(EditorEvent::Edited { transaction_id });
18269            Some(transaction_id)
18270        } else {
18271            None
18272        }
18273    }
18274
18275    pub fn modify_transaction_selection_history(
18276        &mut self,
18277        transaction_id: TransactionId,
18278        modify: impl FnOnce(&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)),
18279    ) -> bool {
18280        self.selection_history
18281            .transaction_mut(transaction_id)
18282            .map(modify)
18283            .is_some()
18284    }
18285
18286    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
18287        if self.selection_mark_mode {
18288            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
18289                s.move_with(|_, sel| {
18290                    sel.collapse_to(sel.head(), SelectionGoal::None);
18291                });
18292            })
18293        }
18294        self.selection_mark_mode = true;
18295        cx.notify();
18296    }
18297
18298    pub fn swap_selection_ends(
18299        &mut self,
18300        _: &actions::SwapSelectionEnds,
18301        window: &mut Window,
18302        cx: &mut Context<Self>,
18303    ) {
18304        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
18305            s.move_with(|_, sel| {
18306                if sel.start != sel.end {
18307                    sel.reversed = !sel.reversed
18308                }
18309            });
18310        });
18311        self.request_autoscroll(Autoscroll::newest(), cx);
18312        cx.notify();
18313    }
18314
18315    pub fn toggle_focus(
18316        workspace: &mut Workspace,
18317        _: &actions::ToggleFocus,
18318        window: &mut Window,
18319        cx: &mut Context<Workspace>,
18320    ) {
18321        let Some(item) = workspace.recent_active_item_by_type::<Self>(cx) else {
18322            return;
18323        };
18324        workspace.activate_item(&item, true, true, window, cx);
18325    }
18326
18327    pub fn toggle_fold(
18328        &mut self,
18329        _: &actions::ToggleFold,
18330        window: &mut Window,
18331        cx: &mut Context<Self>,
18332    ) {
18333        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18334            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18335            let selection = self.selections.newest::<Point>(&display_map);
18336
18337            let range = if selection.is_empty() {
18338                let point = selection.head().to_display_point(&display_map);
18339                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
18340                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
18341                    .to_point(&display_map);
18342                start..end
18343            } else {
18344                selection.range()
18345            };
18346            if display_map.folds_in_range(range).next().is_some() {
18347                self.unfold_lines(&Default::default(), window, cx)
18348            } else {
18349                self.fold(&Default::default(), window, cx)
18350            }
18351        } else {
18352            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18353            let buffer_ids: HashSet<_> = self
18354                .selections
18355                .disjoint_anchor_ranges()
18356                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18357                .collect();
18358
18359            let should_unfold = buffer_ids
18360                .iter()
18361                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
18362
18363            for buffer_id in buffer_ids {
18364                if should_unfold {
18365                    self.unfold_buffer(buffer_id, cx);
18366                } else {
18367                    self.fold_buffer(buffer_id, cx);
18368                }
18369            }
18370        }
18371    }
18372
18373    pub fn toggle_fold_recursive(
18374        &mut self,
18375        _: &actions::ToggleFoldRecursive,
18376        window: &mut Window,
18377        cx: &mut Context<Self>,
18378    ) {
18379        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
18380
18381        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18382        let range = if selection.is_empty() {
18383            let point = selection.head().to_display_point(&display_map);
18384            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
18385            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
18386                .to_point(&display_map);
18387            start..end
18388        } else {
18389            selection.range()
18390        };
18391        if display_map.folds_in_range(range).next().is_some() {
18392            self.unfold_recursive(&Default::default(), window, cx)
18393        } else {
18394            self.fold_recursive(&Default::default(), window, cx)
18395        }
18396    }
18397
18398    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
18399        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18400            let mut to_fold = Vec::new();
18401            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18402            let selections = self.selections.all_adjusted(&display_map);
18403
18404            for selection in selections {
18405                let range = selection.range().sorted();
18406                let buffer_start_row = range.start.row;
18407
18408                if range.start.row != range.end.row {
18409                    let mut found = false;
18410                    let mut row = range.start.row;
18411                    while row <= range.end.row {
18412                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
18413                        {
18414                            found = true;
18415                            row = crease.range().end.row + 1;
18416                            to_fold.push(crease);
18417                        } else {
18418                            row += 1
18419                        }
18420                    }
18421                    if found {
18422                        continue;
18423                    }
18424                }
18425
18426                for row in (0..=range.start.row).rev() {
18427                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
18428                        && crease.range().end.row >= buffer_start_row
18429                    {
18430                        to_fold.push(crease);
18431                        if row <= range.start.row {
18432                            break;
18433                        }
18434                    }
18435                }
18436            }
18437
18438            self.fold_creases(to_fold, true, window, cx);
18439        } else {
18440            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18441            let buffer_ids = self
18442                .selections
18443                .disjoint_anchor_ranges()
18444                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18445                .collect::<HashSet<_>>();
18446            for buffer_id in buffer_ids {
18447                self.fold_buffer(buffer_id, cx);
18448            }
18449        }
18450    }
18451
18452    pub fn toggle_fold_all(
18453        &mut self,
18454        _: &actions::ToggleFoldAll,
18455        window: &mut Window,
18456        cx: &mut Context<Self>,
18457    ) {
18458        if self.buffer.read(cx).is_singleton() {
18459            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18460            let has_folds = display_map
18461                .folds_in_range(0..display_map.buffer_snapshot().len())
18462                .next()
18463                .is_some();
18464
18465            if has_folds {
18466                self.unfold_all(&actions::UnfoldAll, window, cx);
18467            } else {
18468                self.fold_all(&actions::FoldAll, window, cx);
18469            }
18470        } else {
18471            let buffer_ids = self.buffer.read(cx).excerpt_buffer_ids();
18472            let should_unfold = buffer_ids
18473                .iter()
18474                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
18475
18476            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
18477                editor
18478                    .update_in(cx, |editor, _, cx| {
18479                        for buffer_id in buffer_ids {
18480                            if should_unfold {
18481                                editor.unfold_buffer(buffer_id, cx);
18482                            } else {
18483                                editor.fold_buffer(buffer_id, cx);
18484                            }
18485                        }
18486                    })
18487                    .ok();
18488            });
18489        }
18490    }
18491
18492    fn fold_at_level(
18493        &mut self,
18494        fold_at: &FoldAtLevel,
18495        window: &mut Window,
18496        cx: &mut Context<Self>,
18497    ) {
18498        if !self.buffer.read(cx).is_singleton() {
18499            return;
18500        }
18501
18502        let fold_at_level = fold_at.0;
18503        let snapshot = self.buffer.read(cx).snapshot(cx);
18504        let mut to_fold = Vec::new();
18505        let mut stack = vec![(0, snapshot.max_row().0, 1)];
18506
18507        let row_ranges_to_keep: Vec<Range<u32>> = self
18508            .selections
18509            .all::<Point>(&self.display_snapshot(cx))
18510            .into_iter()
18511            .map(|sel| sel.start.row..sel.end.row)
18512            .collect();
18513
18514        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
18515            while start_row < end_row {
18516                match self
18517                    .snapshot(window, cx)
18518                    .crease_for_buffer_row(MultiBufferRow(start_row))
18519                {
18520                    Some(crease) => {
18521                        let nested_start_row = crease.range().start.row + 1;
18522                        let nested_end_row = crease.range().end.row;
18523
18524                        if current_level < fold_at_level {
18525                            stack.push((nested_start_row, nested_end_row, current_level + 1));
18526                        } else if current_level == fold_at_level {
18527                            // Fold iff there is no selection completely contained within the fold region
18528                            if !row_ranges_to_keep.iter().any(|selection| {
18529                                selection.end >= nested_start_row
18530                                    && selection.start <= nested_end_row
18531                            }) {
18532                                to_fold.push(crease);
18533                            }
18534                        }
18535
18536                        start_row = nested_end_row + 1;
18537                    }
18538                    None => start_row += 1,
18539                }
18540            }
18541        }
18542
18543        self.fold_creases(to_fold, true, window, cx);
18544    }
18545
18546    pub fn fold_at_level_1(
18547        &mut self,
18548        _: &actions::FoldAtLevel1,
18549        window: &mut Window,
18550        cx: &mut Context<Self>,
18551    ) {
18552        self.fold_at_level(&actions::FoldAtLevel(1), window, cx);
18553    }
18554
18555    pub fn fold_at_level_2(
18556        &mut self,
18557        _: &actions::FoldAtLevel2,
18558        window: &mut Window,
18559        cx: &mut Context<Self>,
18560    ) {
18561        self.fold_at_level(&actions::FoldAtLevel(2), window, cx);
18562    }
18563
18564    pub fn fold_at_level_3(
18565        &mut self,
18566        _: &actions::FoldAtLevel3,
18567        window: &mut Window,
18568        cx: &mut Context<Self>,
18569    ) {
18570        self.fold_at_level(&actions::FoldAtLevel(3), window, cx);
18571    }
18572
18573    pub fn fold_at_level_4(
18574        &mut self,
18575        _: &actions::FoldAtLevel4,
18576        window: &mut Window,
18577        cx: &mut Context<Self>,
18578    ) {
18579        self.fold_at_level(&actions::FoldAtLevel(4), window, cx);
18580    }
18581
18582    pub fn fold_at_level_5(
18583        &mut self,
18584        _: &actions::FoldAtLevel5,
18585        window: &mut Window,
18586        cx: &mut Context<Self>,
18587    ) {
18588        self.fold_at_level(&actions::FoldAtLevel(5), window, cx);
18589    }
18590
18591    pub fn fold_at_level_6(
18592        &mut self,
18593        _: &actions::FoldAtLevel6,
18594        window: &mut Window,
18595        cx: &mut Context<Self>,
18596    ) {
18597        self.fold_at_level(&actions::FoldAtLevel(6), window, cx);
18598    }
18599
18600    pub fn fold_at_level_7(
18601        &mut self,
18602        _: &actions::FoldAtLevel7,
18603        window: &mut Window,
18604        cx: &mut Context<Self>,
18605    ) {
18606        self.fold_at_level(&actions::FoldAtLevel(7), window, cx);
18607    }
18608
18609    pub fn fold_at_level_8(
18610        &mut self,
18611        _: &actions::FoldAtLevel8,
18612        window: &mut Window,
18613        cx: &mut Context<Self>,
18614    ) {
18615        self.fold_at_level(&actions::FoldAtLevel(8), window, cx);
18616    }
18617
18618    pub fn fold_at_level_9(
18619        &mut self,
18620        _: &actions::FoldAtLevel9,
18621        window: &mut Window,
18622        cx: &mut Context<Self>,
18623    ) {
18624        self.fold_at_level(&actions::FoldAtLevel(9), window, cx);
18625    }
18626
18627    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
18628        if self.buffer.read(cx).is_singleton() {
18629            let mut fold_ranges = Vec::new();
18630            let snapshot = self.buffer.read(cx).snapshot(cx);
18631
18632            for row in 0..snapshot.max_row().0 {
18633                if let Some(foldable_range) = self
18634                    .snapshot(window, cx)
18635                    .crease_for_buffer_row(MultiBufferRow(row))
18636                {
18637                    fold_ranges.push(foldable_range);
18638                }
18639            }
18640
18641            self.fold_creases(fold_ranges, true, window, cx);
18642        } else {
18643            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
18644                editor
18645                    .update_in(cx, |editor, _, cx| {
18646                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
18647                            editor.fold_buffer(buffer_id, cx);
18648                        }
18649                    })
18650                    .ok();
18651            });
18652        }
18653    }
18654
18655    pub fn fold_function_bodies(
18656        &mut self,
18657        _: &actions::FoldFunctionBodies,
18658        window: &mut Window,
18659        cx: &mut Context<Self>,
18660    ) {
18661        let snapshot = self.buffer.read(cx).snapshot(cx);
18662
18663        let ranges = snapshot
18664            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
18665            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
18666            .collect::<Vec<_>>();
18667
18668        let creases = ranges
18669            .into_iter()
18670            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
18671            .collect();
18672
18673        self.fold_creases(creases, true, window, cx);
18674    }
18675
18676    pub fn fold_recursive(
18677        &mut self,
18678        _: &actions::FoldRecursive,
18679        window: &mut Window,
18680        cx: &mut Context<Self>,
18681    ) {
18682        let mut to_fold = Vec::new();
18683        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18684        let selections = self.selections.all_adjusted(&display_map);
18685
18686        for selection in selections {
18687            let range = selection.range().sorted();
18688            let buffer_start_row = range.start.row;
18689
18690            if range.start.row != range.end.row {
18691                let mut found = false;
18692                for row in range.start.row..=range.end.row {
18693                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
18694                        found = true;
18695                        to_fold.push(crease);
18696                    }
18697                }
18698                if found {
18699                    continue;
18700                }
18701            }
18702
18703            for row in (0..=range.start.row).rev() {
18704                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
18705                    if crease.range().end.row >= buffer_start_row {
18706                        to_fold.push(crease);
18707                    } else {
18708                        break;
18709                    }
18710                }
18711            }
18712        }
18713
18714        self.fold_creases(to_fold, true, window, cx);
18715    }
18716
18717    pub fn fold_at(
18718        &mut self,
18719        buffer_row: MultiBufferRow,
18720        window: &mut Window,
18721        cx: &mut Context<Self>,
18722    ) {
18723        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18724
18725        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
18726            let autoscroll = self
18727                .selections
18728                .all::<Point>(&display_map)
18729                .iter()
18730                .any(|selection| crease.range().overlaps(&selection.range()));
18731
18732            self.fold_creases(vec![crease], autoscroll, window, cx);
18733        }
18734    }
18735
18736    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
18737        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18738            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18739            let buffer = display_map.buffer_snapshot();
18740            let selections = self.selections.all::<Point>(&display_map);
18741            let ranges = selections
18742                .iter()
18743                .map(|s| {
18744                    let range = s.display_range(&display_map).sorted();
18745                    let mut start = range.start.to_point(&display_map);
18746                    let mut end = range.end.to_point(&display_map);
18747                    start.column = 0;
18748                    end.column = buffer.line_len(MultiBufferRow(end.row));
18749                    start..end
18750                })
18751                .collect::<Vec<_>>();
18752
18753            self.unfold_ranges(&ranges, true, true, cx);
18754        } else {
18755            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18756            let buffer_ids = self
18757                .selections
18758                .disjoint_anchor_ranges()
18759                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18760                .collect::<HashSet<_>>();
18761            for buffer_id in buffer_ids {
18762                self.unfold_buffer(buffer_id, cx);
18763            }
18764        }
18765    }
18766
18767    pub fn unfold_recursive(
18768        &mut self,
18769        _: &UnfoldRecursive,
18770        _window: &mut Window,
18771        cx: &mut Context<Self>,
18772    ) {
18773        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18774        let selections = self.selections.all::<Point>(&display_map);
18775        let ranges = selections
18776            .iter()
18777            .map(|s| {
18778                let mut range = s.display_range(&display_map).sorted();
18779                *range.start.column_mut() = 0;
18780                *range.end.column_mut() = display_map.line_len(range.end.row());
18781                let start = range.start.to_point(&display_map);
18782                let end = range.end.to_point(&display_map);
18783                start..end
18784            })
18785            .collect::<Vec<_>>();
18786
18787        self.unfold_ranges(&ranges, true, true, cx);
18788    }
18789
18790    pub fn unfold_at(
18791        &mut self,
18792        buffer_row: MultiBufferRow,
18793        _window: &mut Window,
18794        cx: &mut Context<Self>,
18795    ) {
18796        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18797
18798        let intersection_range = Point::new(buffer_row.0, 0)
18799            ..Point::new(
18800                buffer_row.0,
18801                display_map.buffer_snapshot().line_len(buffer_row),
18802            );
18803
18804        let autoscroll = self
18805            .selections
18806            .all::<Point>(&display_map)
18807            .iter()
18808            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
18809
18810        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
18811    }
18812
18813    pub fn unfold_all(
18814        &mut self,
18815        _: &actions::UnfoldAll,
18816        _window: &mut Window,
18817        cx: &mut Context<Self>,
18818    ) {
18819        if self.buffer.read(cx).is_singleton() {
18820            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18821            self.unfold_ranges(&[0..display_map.buffer_snapshot().len()], true, true, cx);
18822        } else {
18823            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
18824                editor
18825                    .update(cx, |editor, cx| {
18826                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
18827                            editor.unfold_buffer(buffer_id, cx);
18828                        }
18829                    })
18830                    .ok();
18831            });
18832        }
18833    }
18834
18835    pub fn fold_selected_ranges(
18836        &mut self,
18837        _: &FoldSelectedRanges,
18838        window: &mut Window,
18839        cx: &mut Context<Self>,
18840    ) {
18841        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18842        let selections = self.selections.all_adjusted(&display_map);
18843        let ranges = selections
18844            .into_iter()
18845            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
18846            .collect::<Vec<_>>();
18847        self.fold_creases(ranges, true, window, cx);
18848    }
18849
18850    pub fn fold_ranges<T: ToOffset + Clone>(
18851        &mut self,
18852        ranges: Vec<Range<T>>,
18853        auto_scroll: bool,
18854        window: &mut Window,
18855        cx: &mut Context<Self>,
18856    ) {
18857        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18858        let ranges = ranges
18859            .into_iter()
18860            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
18861            .collect::<Vec<_>>();
18862        self.fold_creases(ranges, auto_scroll, window, cx);
18863    }
18864
18865    pub fn fold_creases<T: ToOffset + Clone>(
18866        &mut self,
18867        creases: Vec<Crease<T>>,
18868        auto_scroll: bool,
18869        _window: &mut Window,
18870        cx: &mut Context<Self>,
18871    ) {
18872        if creases.is_empty() {
18873            return;
18874        }
18875
18876        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
18877
18878        if auto_scroll {
18879            self.request_autoscroll(Autoscroll::fit(), cx);
18880        }
18881
18882        cx.notify();
18883
18884        self.scrollbar_marker_state.dirty = true;
18885        self.folds_did_change(cx);
18886    }
18887
18888    /// Removes any folds whose ranges intersect any of the given ranges.
18889    pub fn unfold_ranges<T: ToOffset + Clone>(
18890        &mut self,
18891        ranges: &[Range<T>],
18892        inclusive: bool,
18893        auto_scroll: bool,
18894        cx: &mut Context<Self>,
18895    ) {
18896        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
18897            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
18898        });
18899        self.folds_did_change(cx);
18900    }
18901
18902    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18903        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
18904            return;
18905        }
18906
18907        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
18908        self.display_map.update(cx, |display_map, cx| {
18909            display_map.fold_buffers([buffer_id], cx)
18910        });
18911
18912        let snapshot = self.display_snapshot(cx);
18913        self.selections.change_with(&snapshot, |selections| {
18914            selections.remove_selections_from_buffer(buffer_id);
18915        });
18916
18917        cx.emit(EditorEvent::BufferFoldToggled {
18918            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
18919            folded: true,
18920        });
18921        cx.notify();
18922    }
18923
18924    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18925        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
18926            return;
18927        }
18928        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
18929        self.display_map.update(cx, |display_map, cx| {
18930            display_map.unfold_buffers([buffer_id], cx);
18931        });
18932        cx.emit(EditorEvent::BufferFoldToggled {
18933            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
18934            folded: false,
18935        });
18936        cx.notify();
18937    }
18938
18939    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
18940        self.display_map.read(cx).is_buffer_folded(buffer)
18941    }
18942
18943    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
18944        self.display_map.read(cx).folded_buffers()
18945    }
18946
18947    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18948        self.display_map.update(cx, |display_map, cx| {
18949            display_map.disable_header_for_buffer(buffer_id, cx);
18950        });
18951        cx.notify();
18952    }
18953
18954    /// Removes any folds with the given ranges.
18955    pub fn remove_folds_with_type<T: ToOffset + Clone>(
18956        &mut self,
18957        ranges: &[Range<T>],
18958        type_id: TypeId,
18959        auto_scroll: bool,
18960        cx: &mut Context<Self>,
18961    ) {
18962        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
18963            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
18964        });
18965        self.folds_did_change(cx);
18966    }
18967
18968    fn remove_folds_with<T: ToOffset + Clone>(
18969        &mut self,
18970        ranges: &[Range<T>],
18971        auto_scroll: bool,
18972        cx: &mut Context<Self>,
18973        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
18974    ) {
18975        if ranges.is_empty() {
18976            return;
18977        }
18978
18979        let mut buffers_affected = HashSet::default();
18980        let multi_buffer = self.buffer().read(cx);
18981        for range in ranges {
18982            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
18983                buffers_affected.insert(buffer.read(cx).remote_id());
18984            };
18985        }
18986
18987        self.display_map.update(cx, update);
18988
18989        if auto_scroll {
18990            self.request_autoscroll(Autoscroll::fit(), cx);
18991        }
18992
18993        cx.notify();
18994        self.scrollbar_marker_state.dirty = true;
18995        self.active_indent_guides_state.dirty = true;
18996    }
18997
18998    pub fn update_renderer_widths(
18999        &mut self,
19000        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
19001        cx: &mut Context<Self>,
19002    ) -> bool {
19003        self.display_map
19004            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
19005    }
19006
19007    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
19008        self.display_map.read(cx).fold_placeholder.clone()
19009    }
19010
19011    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
19012        self.buffer.update(cx, |buffer, cx| {
19013            buffer.set_all_diff_hunks_expanded(cx);
19014        });
19015    }
19016
19017    pub fn expand_all_diff_hunks(
19018        &mut self,
19019        _: &ExpandAllDiffHunks,
19020        _window: &mut Window,
19021        cx: &mut Context<Self>,
19022    ) {
19023        self.buffer.update(cx, |buffer, cx| {
19024            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
19025        });
19026    }
19027
19028    pub fn collapse_all_diff_hunks(
19029        &mut self,
19030        _: &CollapseAllDiffHunks,
19031        _window: &mut Window,
19032        cx: &mut Context<Self>,
19033    ) {
19034        self.buffer.update(cx, |buffer, cx| {
19035            buffer.collapse_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
19036        });
19037    }
19038
19039    pub fn toggle_selected_diff_hunks(
19040        &mut self,
19041        _: &ToggleSelectedDiffHunks,
19042        _window: &mut Window,
19043        cx: &mut Context<Self>,
19044    ) {
19045        let ranges: Vec<_> = self
19046            .selections
19047            .disjoint_anchors()
19048            .iter()
19049            .map(|s| s.range())
19050            .collect();
19051        self.toggle_diff_hunks_in_ranges(ranges, cx);
19052    }
19053
19054    pub fn diff_hunks_in_ranges<'a>(
19055        &'a self,
19056        ranges: &'a [Range<Anchor>],
19057        buffer: &'a MultiBufferSnapshot,
19058    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
19059        ranges.iter().flat_map(move |range| {
19060            let end_excerpt_id = range.end.excerpt_id;
19061            let range = range.to_point(buffer);
19062            let mut peek_end = range.end;
19063            if range.end.row < buffer.max_row().0 {
19064                peek_end = Point::new(range.end.row + 1, 0);
19065            }
19066            buffer
19067                .diff_hunks_in_range(range.start..peek_end)
19068                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
19069        })
19070    }
19071
19072    pub fn has_stageable_diff_hunks_in_ranges(
19073        &self,
19074        ranges: &[Range<Anchor>],
19075        snapshot: &MultiBufferSnapshot,
19076    ) -> bool {
19077        let mut hunks = self.diff_hunks_in_ranges(ranges, snapshot);
19078        hunks.any(|hunk| hunk.status().has_secondary_hunk())
19079    }
19080
19081    pub fn toggle_staged_selected_diff_hunks(
19082        &mut self,
19083        _: &::git::ToggleStaged,
19084        _: &mut Window,
19085        cx: &mut Context<Self>,
19086    ) {
19087        let snapshot = self.buffer.read(cx).snapshot(cx);
19088        let ranges: Vec<_> = self
19089            .selections
19090            .disjoint_anchors()
19091            .iter()
19092            .map(|s| s.range())
19093            .collect();
19094        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
19095        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
19096    }
19097
19098    pub fn set_render_diff_hunk_controls(
19099        &mut self,
19100        render_diff_hunk_controls: RenderDiffHunkControlsFn,
19101        cx: &mut Context<Self>,
19102    ) {
19103        self.render_diff_hunk_controls = render_diff_hunk_controls;
19104        cx.notify();
19105    }
19106
19107    pub fn stage_and_next(
19108        &mut self,
19109        _: &::git::StageAndNext,
19110        window: &mut Window,
19111        cx: &mut Context<Self>,
19112    ) {
19113        self.do_stage_or_unstage_and_next(true, window, cx);
19114    }
19115
19116    pub fn unstage_and_next(
19117        &mut self,
19118        _: &::git::UnstageAndNext,
19119        window: &mut Window,
19120        cx: &mut Context<Self>,
19121    ) {
19122        self.do_stage_or_unstage_and_next(false, window, cx);
19123    }
19124
19125    pub fn stage_or_unstage_diff_hunks(
19126        &mut self,
19127        stage: bool,
19128        ranges: Vec<Range<Anchor>>,
19129        cx: &mut Context<Self>,
19130    ) {
19131        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
19132        cx.spawn(async move |this, cx| {
19133            task.await?;
19134            this.update(cx, |this, cx| {
19135                let snapshot = this.buffer.read(cx).snapshot(cx);
19136                let chunk_by = this
19137                    .diff_hunks_in_ranges(&ranges, &snapshot)
19138                    .chunk_by(|hunk| hunk.buffer_id);
19139                for (buffer_id, hunks) in &chunk_by {
19140                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
19141                }
19142            })
19143        })
19144        .detach_and_log_err(cx);
19145    }
19146
19147    fn save_buffers_for_ranges_if_needed(
19148        &mut self,
19149        ranges: &[Range<Anchor>],
19150        cx: &mut Context<Editor>,
19151    ) -> Task<Result<()>> {
19152        let multibuffer = self.buffer.read(cx);
19153        let snapshot = multibuffer.read(cx);
19154        let buffer_ids: HashSet<_> = ranges
19155            .iter()
19156            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
19157            .collect();
19158        drop(snapshot);
19159
19160        let mut buffers = HashSet::default();
19161        for buffer_id in buffer_ids {
19162            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
19163                let buffer = buffer_entity.read(cx);
19164                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
19165                {
19166                    buffers.insert(buffer_entity);
19167                }
19168            }
19169        }
19170
19171        if let Some(project) = &self.project {
19172            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
19173        } else {
19174            Task::ready(Ok(()))
19175        }
19176    }
19177
19178    fn do_stage_or_unstage_and_next(
19179        &mut self,
19180        stage: bool,
19181        window: &mut Window,
19182        cx: &mut Context<Self>,
19183    ) {
19184        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
19185
19186        if ranges.iter().any(|range| range.start != range.end) {
19187            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
19188            return;
19189        }
19190
19191        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
19192        let snapshot = self.snapshot(window, cx);
19193        let position = self
19194            .selections
19195            .newest::<Point>(&snapshot.display_snapshot)
19196            .head();
19197        let mut row = snapshot
19198            .buffer_snapshot()
19199            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
19200            .find(|hunk| hunk.row_range.start.0 > position.row)
19201            .map(|hunk| hunk.row_range.start);
19202
19203        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
19204        // Outside of the project diff editor, wrap around to the beginning.
19205        if !all_diff_hunks_expanded {
19206            row = row.or_else(|| {
19207                snapshot
19208                    .buffer_snapshot()
19209                    .diff_hunks_in_range(Point::zero()..position)
19210                    .find(|hunk| hunk.row_range.end.0 < position.row)
19211                    .map(|hunk| hunk.row_range.start)
19212            });
19213        }
19214
19215        if let Some(row) = row {
19216            let destination = Point::new(row.0, 0);
19217            let autoscroll = Autoscroll::center();
19218
19219            self.unfold_ranges(&[destination..destination], false, false, cx);
19220            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
19221                s.select_ranges([destination..destination]);
19222            });
19223        }
19224    }
19225
19226    fn do_stage_or_unstage(
19227        &self,
19228        stage: bool,
19229        buffer_id: BufferId,
19230        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
19231        cx: &mut App,
19232    ) -> Option<()> {
19233        let project = self.project()?;
19234        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
19235        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
19236        let buffer_snapshot = buffer.read(cx).snapshot();
19237        let file_exists = buffer_snapshot
19238            .file()
19239            .is_some_and(|file| file.disk_state().exists());
19240        diff.update(cx, |diff, cx| {
19241            diff.stage_or_unstage_hunks(
19242                stage,
19243                &hunks
19244                    .map(|hunk| buffer_diff::DiffHunk {
19245                        buffer_range: hunk.buffer_range,
19246                        diff_base_byte_range: hunk.diff_base_byte_range,
19247                        secondary_status: hunk.secondary_status,
19248                        range: Point::zero()..Point::zero(), // unused
19249                    })
19250                    .collect::<Vec<_>>(),
19251                &buffer_snapshot,
19252                file_exists,
19253                cx,
19254            )
19255        });
19256        None
19257    }
19258
19259    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
19260        let ranges: Vec<_> = self
19261            .selections
19262            .disjoint_anchors()
19263            .iter()
19264            .map(|s| s.range())
19265            .collect();
19266        self.buffer
19267            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
19268    }
19269
19270    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
19271        self.buffer.update(cx, |buffer, cx| {
19272            let ranges = vec![Anchor::min()..Anchor::max()];
19273            if !buffer.all_diff_hunks_expanded()
19274                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
19275            {
19276                buffer.collapse_diff_hunks(ranges, cx);
19277                true
19278            } else {
19279                false
19280            }
19281        })
19282    }
19283
19284    fn toggle_diff_hunks_in_ranges(
19285        &mut self,
19286        ranges: Vec<Range<Anchor>>,
19287        cx: &mut Context<Editor>,
19288    ) {
19289        self.buffer.update(cx, |buffer, cx| {
19290            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
19291            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
19292        })
19293    }
19294
19295    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
19296        self.buffer.update(cx, |buffer, cx| {
19297            let snapshot = buffer.snapshot(cx);
19298            let excerpt_id = range.end.excerpt_id;
19299            let point_range = range.to_point(&snapshot);
19300            let expand = !buffer.single_hunk_is_expanded(range, cx);
19301            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
19302        })
19303    }
19304
19305    pub(crate) fn apply_all_diff_hunks(
19306        &mut self,
19307        _: &ApplyAllDiffHunks,
19308        window: &mut Window,
19309        cx: &mut Context<Self>,
19310    ) {
19311        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19312
19313        let buffers = self.buffer.read(cx).all_buffers();
19314        for branch_buffer in buffers {
19315            branch_buffer.update(cx, |branch_buffer, cx| {
19316                branch_buffer.merge_into_base(Vec::new(), cx);
19317            });
19318        }
19319
19320        if let Some(project) = self.project.clone() {
19321            self.save(
19322                SaveOptions {
19323                    format: true,
19324                    autosave: false,
19325                },
19326                project,
19327                window,
19328                cx,
19329            )
19330            .detach_and_log_err(cx);
19331        }
19332    }
19333
19334    pub(crate) fn apply_selected_diff_hunks(
19335        &mut self,
19336        _: &ApplyDiffHunk,
19337        window: &mut Window,
19338        cx: &mut Context<Self>,
19339    ) {
19340        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19341        let snapshot = self.snapshot(window, cx);
19342        let hunks = snapshot.hunks_for_ranges(
19343            self.selections
19344                .all(&snapshot.display_snapshot)
19345                .into_iter()
19346                .map(|selection| selection.range()),
19347        );
19348        let mut ranges_by_buffer = HashMap::default();
19349        self.transact(window, cx, |editor, _window, cx| {
19350            for hunk in hunks {
19351                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
19352                    ranges_by_buffer
19353                        .entry(buffer.clone())
19354                        .or_insert_with(Vec::new)
19355                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
19356                }
19357            }
19358
19359            for (buffer, ranges) in ranges_by_buffer {
19360                buffer.update(cx, |buffer, cx| {
19361                    buffer.merge_into_base(ranges, cx);
19362                });
19363            }
19364        });
19365
19366        if let Some(project) = self.project.clone() {
19367            self.save(
19368                SaveOptions {
19369                    format: true,
19370                    autosave: false,
19371                },
19372                project,
19373                window,
19374                cx,
19375            )
19376            .detach_and_log_err(cx);
19377        }
19378    }
19379
19380    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
19381        if hovered != self.gutter_hovered {
19382            self.gutter_hovered = hovered;
19383            cx.notify();
19384        }
19385    }
19386
19387    pub fn insert_blocks(
19388        &mut self,
19389        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
19390        autoscroll: Option<Autoscroll>,
19391        cx: &mut Context<Self>,
19392    ) -> Vec<CustomBlockId> {
19393        let blocks = self
19394            .display_map
19395            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
19396        if let Some(autoscroll) = autoscroll {
19397            self.request_autoscroll(autoscroll, cx);
19398        }
19399        cx.notify();
19400        blocks
19401    }
19402
19403    pub fn resize_blocks(
19404        &mut self,
19405        heights: HashMap<CustomBlockId, u32>,
19406        autoscroll: Option<Autoscroll>,
19407        cx: &mut Context<Self>,
19408    ) {
19409        self.display_map
19410            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
19411        if let Some(autoscroll) = autoscroll {
19412            self.request_autoscroll(autoscroll, cx);
19413        }
19414        cx.notify();
19415    }
19416
19417    pub fn replace_blocks(
19418        &mut self,
19419        renderers: HashMap<CustomBlockId, RenderBlock>,
19420        autoscroll: Option<Autoscroll>,
19421        cx: &mut Context<Self>,
19422    ) {
19423        self.display_map
19424            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
19425        if let Some(autoscroll) = autoscroll {
19426            self.request_autoscroll(autoscroll, cx);
19427        }
19428        cx.notify();
19429    }
19430
19431    pub fn remove_blocks(
19432        &mut self,
19433        block_ids: HashSet<CustomBlockId>,
19434        autoscroll: Option<Autoscroll>,
19435        cx: &mut Context<Self>,
19436    ) {
19437        self.display_map.update(cx, |display_map, cx| {
19438            display_map.remove_blocks(block_ids, cx)
19439        });
19440        if let Some(autoscroll) = autoscroll {
19441            self.request_autoscroll(autoscroll, cx);
19442        }
19443        cx.notify();
19444    }
19445
19446    pub fn row_for_block(
19447        &self,
19448        block_id: CustomBlockId,
19449        cx: &mut Context<Self>,
19450    ) -> Option<DisplayRow> {
19451        self.display_map
19452            .update(cx, |map, cx| map.row_for_block(block_id, cx))
19453    }
19454
19455    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
19456        self.focused_block = Some(focused_block);
19457    }
19458
19459    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
19460        self.focused_block.take()
19461    }
19462
19463    pub fn insert_creases(
19464        &mut self,
19465        creases: impl IntoIterator<Item = Crease<Anchor>>,
19466        cx: &mut Context<Self>,
19467    ) -> Vec<CreaseId> {
19468        self.display_map
19469            .update(cx, |map, cx| map.insert_creases(creases, cx))
19470    }
19471
19472    pub fn remove_creases(
19473        &mut self,
19474        ids: impl IntoIterator<Item = CreaseId>,
19475        cx: &mut Context<Self>,
19476    ) -> Vec<(CreaseId, Range<Anchor>)> {
19477        self.display_map
19478            .update(cx, |map, cx| map.remove_creases(ids, cx))
19479    }
19480
19481    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
19482        self.display_map
19483            .update(cx, |map, cx| map.snapshot(cx))
19484            .longest_row()
19485    }
19486
19487    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
19488        self.display_map
19489            .update(cx, |map, cx| map.snapshot(cx))
19490            .max_point()
19491    }
19492
19493    pub fn text(&self, cx: &App) -> String {
19494        self.buffer.read(cx).read(cx).text()
19495    }
19496
19497    pub fn is_empty(&self, cx: &App) -> bool {
19498        self.buffer.read(cx).read(cx).is_empty()
19499    }
19500
19501    pub fn text_option(&self, cx: &App) -> Option<String> {
19502        let text = self.text(cx);
19503        let text = text.trim();
19504
19505        if text.is_empty() {
19506            return None;
19507        }
19508
19509        Some(text.to_string())
19510    }
19511
19512    pub fn set_text(
19513        &mut self,
19514        text: impl Into<Arc<str>>,
19515        window: &mut Window,
19516        cx: &mut Context<Self>,
19517    ) {
19518        self.transact(window, cx, |this, _, cx| {
19519            this.buffer
19520                .read(cx)
19521                .as_singleton()
19522                .expect("you can only call set_text on editors for singleton buffers")
19523                .update(cx, |buffer, cx| buffer.set_text(text, cx));
19524        });
19525    }
19526
19527    pub fn display_text(&self, cx: &mut App) -> String {
19528        self.display_map
19529            .update(cx, |map, cx| map.snapshot(cx))
19530            .text()
19531    }
19532
19533    fn create_minimap(
19534        &self,
19535        minimap_settings: MinimapSettings,
19536        window: &mut Window,
19537        cx: &mut Context<Self>,
19538    ) -> Option<Entity<Self>> {
19539        (minimap_settings.minimap_enabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton)
19540            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
19541    }
19542
19543    fn initialize_new_minimap(
19544        &self,
19545        minimap_settings: MinimapSettings,
19546        window: &mut Window,
19547        cx: &mut Context<Self>,
19548    ) -> Entity<Self> {
19549        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
19550
19551        let mut minimap = Editor::new_internal(
19552            EditorMode::Minimap {
19553                parent: cx.weak_entity(),
19554            },
19555            self.buffer.clone(),
19556            None,
19557            Some(self.display_map.clone()),
19558            window,
19559            cx,
19560        );
19561        minimap.scroll_manager.clone_state(&self.scroll_manager);
19562        minimap.set_text_style_refinement(TextStyleRefinement {
19563            font_size: Some(MINIMAP_FONT_SIZE),
19564            font_weight: Some(MINIMAP_FONT_WEIGHT),
19565            ..Default::default()
19566        });
19567        minimap.update_minimap_configuration(minimap_settings, cx);
19568        cx.new(|_| minimap)
19569    }
19570
19571    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
19572        let current_line_highlight = minimap_settings
19573            .current_line_highlight
19574            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
19575        self.set_current_line_highlight(Some(current_line_highlight));
19576    }
19577
19578    pub fn minimap(&self) -> Option<&Entity<Self>> {
19579        self.minimap
19580            .as_ref()
19581            .filter(|_| self.minimap_visibility.visible())
19582    }
19583
19584    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
19585        let mut wrap_guides = smallvec![];
19586
19587        if self.show_wrap_guides == Some(false) {
19588            return wrap_guides;
19589        }
19590
19591        let settings = self.buffer.read(cx).language_settings(cx);
19592        if settings.show_wrap_guides {
19593            match self.soft_wrap_mode(cx) {
19594                SoftWrap::Column(soft_wrap) => {
19595                    wrap_guides.push((soft_wrap as usize, true));
19596                }
19597                SoftWrap::Bounded(soft_wrap) => {
19598                    wrap_guides.push((soft_wrap as usize, true));
19599                }
19600                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
19601            }
19602            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
19603        }
19604
19605        wrap_guides
19606    }
19607
19608    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
19609        let settings = self.buffer.read(cx).language_settings(cx);
19610        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
19611        match mode {
19612            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
19613                SoftWrap::None
19614            }
19615            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
19616            language_settings::SoftWrap::PreferredLineLength => {
19617                SoftWrap::Column(settings.preferred_line_length)
19618            }
19619            language_settings::SoftWrap::Bounded => {
19620                SoftWrap::Bounded(settings.preferred_line_length)
19621            }
19622        }
19623    }
19624
19625    pub fn set_soft_wrap_mode(
19626        &mut self,
19627        mode: language_settings::SoftWrap,
19628
19629        cx: &mut Context<Self>,
19630    ) {
19631        self.soft_wrap_mode_override = Some(mode);
19632        cx.notify();
19633    }
19634
19635    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
19636        self.hard_wrap = hard_wrap;
19637        cx.notify();
19638    }
19639
19640    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
19641        self.text_style_refinement = Some(style);
19642    }
19643
19644    /// called by the Element so we know what style we were most recently rendered with.
19645    pub fn set_style(&mut self, style: EditorStyle, window: &mut Window, cx: &mut Context<Self>) {
19646        // We intentionally do not inform the display map about the minimap style
19647        // so that wrapping is not recalculated and stays consistent for the editor
19648        // and its linked minimap.
19649        if !self.mode.is_minimap() {
19650            let font = style.text.font();
19651            let font_size = style.text.font_size.to_pixels(window.rem_size());
19652            let display_map = self
19653                .placeholder_display_map
19654                .as_ref()
19655                .filter(|_| self.is_empty(cx))
19656                .unwrap_or(&self.display_map);
19657
19658            display_map.update(cx, |map, cx| map.set_font(font, font_size, cx));
19659        }
19660        self.style = Some(style);
19661    }
19662
19663    pub fn style(&self) -> Option<&EditorStyle> {
19664        self.style.as_ref()
19665    }
19666
19667    // Called by the element. This method is not designed to be called outside of the editor
19668    // element's layout code because it does not notify when rewrapping is computed synchronously.
19669    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
19670        if self.is_empty(cx) {
19671            self.placeholder_display_map
19672                .as_ref()
19673                .map_or(false, |display_map| {
19674                    display_map.update(cx, |map, cx| map.set_wrap_width(width, cx))
19675                })
19676        } else {
19677            self.display_map
19678                .update(cx, |map, cx| map.set_wrap_width(width, cx))
19679        }
19680    }
19681
19682    pub fn set_soft_wrap(&mut self) {
19683        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
19684    }
19685
19686    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
19687        if self.soft_wrap_mode_override.is_some() {
19688            self.soft_wrap_mode_override.take();
19689        } else {
19690            let soft_wrap = match self.soft_wrap_mode(cx) {
19691                SoftWrap::GitDiff => return,
19692                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
19693                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
19694                    language_settings::SoftWrap::None
19695                }
19696            };
19697            self.soft_wrap_mode_override = Some(soft_wrap);
19698        }
19699        cx.notify();
19700    }
19701
19702    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
19703        let Some(workspace) = self.workspace() else {
19704            return;
19705        };
19706        let fs = workspace.read(cx).app_state().fs.clone();
19707        let current_show = TabBarSettings::get_global(cx).show;
19708        update_settings_file(fs, cx, move |setting, _| {
19709            setting.tab_bar.get_or_insert_default().show = Some(!current_show);
19710        });
19711    }
19712
19713    pub fn toggle_indent_guides(
19714        &mut self,
19715        _: &ToggleIndentGuides,
19716        _: &mut Window,
19717        cx: &mut Context<Self>,
19718    ) {
19719        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
19720            self.buffer
19721                .read(cx)
19722                .language_settings(cx)
19723                .indent_guides
19724                .enabled
19725        });
19726        self.show_indent_guides = Some(!currently_enabled);
19727        cx.notify();
19728    }
19729
19730    fn should_show_indent_guides(&self) -> Option<bool> {
19731        self.show_indent_guides
19732    }
19733
19734    pub fn toggle_line_numbers(
19735        &mut self,
19736        _: &ToggleLineNumbers,
19737        _: &mut Window,
19738        cx: &mut Context<Self>,
19739    ) {
19740        let mut editor_settings = EditorSettings::get_global(cx).clone();
19741        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
19742        EditorSettings::override_global(editor_settings, cx);
19743    }
19744
19745    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
19746        if let Some(show_line_numbers) = self.show_line_numbers {
19747            return show_line_numbers;
19748        }
19749        EditorSettings::get_global(cx).gutter.line_numbers
19750    }
19751
19752    pub fn relative_line_numbers(&self, cx: &mut App) -> RelativeLineNumbers {
19753        match (
19754            self.use_relative_line_numbers,
19755            EditorSettings::get_global(cx).relative_line_numbers,
19756        ) {
19757            (None, setting) => setting,
19758            (Some(false), _) => RelativeLineNumbers::Disabled,
19759            (Some(true), RelativeLineNumbers::Wrapped) => RelativeLineNumbers::Wrapped,
19760            (Some(true), _) => RelativeLineNumbers::Enabled,
19761        }
19762    }
19763
19764    pub fn toggle_relative_line_numbers(
19765        &mut self,
19766        _: &ToggleRelativeLineNumbers,
19767        _: &mut Window,
19768        cx: &mut Context<Self>,
19769    ) {
19770        let is_relative = self.relative_line_numbers(cx);
19771        self.set_relative_line_number(Some(!is_relative.enabled()), cx)
19772    }
19773
19774    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
19775        self.use_relative_line_numbers = is_relative;
19776        cx.notify();
19777    }
19778
19779    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
19780        self.show_gutter = show_gutter;
19781        cx.notify();
19782    }
19783
19784    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
19785        self.show_scrollbars = ScrollbarAxes {
19786            horizontal: show,
19787            vertical: show,
19788        };
19789        cx.notify();
19790    }
19791
19792    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
19793        self.show_scrollbars.vertical = show;
19794        cx.notify();
19795    }
19796
19797    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
19798        self.show_scrollbars.horizontal = show;
19799        cx.notify();
19800    }
19801
19802    pub fn set_minimap_visibility(
19803        &mut self,
19804        minimap_visibility: MinimapVisibility,
19805        window: &mut Window,
19806        cx: &mut Context<Self>,
19807    ) {
19808        if self.minimap_visibility != minimap_visibility {
19809            if minimap_visibility.visible() && self.minimap.is_none() {
19810                let minimap_settings = EditorSettings::get_global(cx).minimap;
19811                self.minimap =
19812                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
19813            }
19814            self.minimap_visibility = minimap_visibility;
19815            cx.notify();
19816        }
19817    }
19818
19819    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19820        self.set_show_scrollbars(false, cx);
19821        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
19822    }
19823
19824    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19825        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
19826    }
19827
19828    /// Normally the text in full mode and auto height editors is padded on the
19829    /// left side by roughly half a character width for improved hit testing.
19830    ///
19831    /// Use this method to disable this for cases where this is not wanted (e.g.
19832    /// if you want to align the editor text with some other text above or below)
19833    /// or if you want to add this padding to single-line editors.
19834    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
19835        self.offset_content = offset_content;
19836        cx.notify();
19837    }
19838
19839    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
19840        self.show_line_numbers = Some(show_line_numbers);
19841        cx.notify();
19842    }
19843
19844    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
19845        self.disable_expand_excerpt_buttons = true;
19846        cx.notify();
19847    }
19848
19849    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
19850        self.show_git_diff_gutter = Some(show_git_diff_gutter);
19851        cx.notify();
19852    }
19853
19854    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
19855        self.show_code_actions = Some(show_code_actions);
19856        cx.notify();
19857    }
19858
19859    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
19860        self.show_runnables = Some(show_runnables);
19861        cx.notify();
19862    }
19863
19864    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
19865        self.show_breakpoints = Some(show_breakpoints);
19866        cx.notify();
19867    }
19868
19869    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
19870        if self.display_map.read(cx).masked != masked {
19871            self.display_map.update(cx, |map, _| map.masked = masked);
19872        }
19873        cx.notify()
19874    }
19875
19876    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
19877        self.show_wrap_guides = Some(show_wrap_guides);
19878        cx.notify();
19879    }
19880
19881    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
19882        self.show_indent_guides = Some(show_indent_guides);
19883        cx.notify();
19884    }
19885
19886    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
19887        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
19888            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local())
19889                && let Some(dir) = file.abs_path(cx).parent()
19890            {
19891                return Some(dir.to_owned());
19892            }
19893        }
19894
19895        None
19896    }
19897
19898    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
19899        self.active_excerpt(cx)?
19900            .1
19901            .read(cx)
19902            .file()
19903            .and_then(|f| f.as_local())
19904    }
19905
19906    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
19907        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
19908            let buffer = buffer.read(cx);
19909            if let Some(project_path) = buffer.project_path(cx) {
19910                let project = self.project()?.read(cx);
19911                project.absolute_path(&project_path, cx)
19912            } else {
19913                buffer
19914                    .file()
19915                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
19916            }
19917        })
19918    }
19919
19920    pub fn reveal_in_finder(
19921        &mut self,
19922        _: &RevealInFileManager,
19923        _window: &mut Window,
19924        cx: &mut Context<Self>,
19925    ) {
19926        if let Some(target) = self.target_file(cx) {
19927            cx.reveal_path(&target.abs_path(cx));
19928        }
19929    }
19930
19931    pub fn copy_path(
19932        &mut self,
19933        _: &zed_actions::workspace::CopyPath,
19934        _window: &mut Window,
19935        cx: &mut Context<Self>,
19936    ) {
19937        if let Some(path) = self.target_file_abs_path(cx)
19938            && let Some(path) = path.to_str()
19939        {
19940            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
19941        } else {
19942            cx.propagate();
19943        }
19944    }
19945
19946    pub fn copy_relative_path(
19947        &mut self,
19948        _: &zed_actions::workspace::CopyRelativePath,
19949        _window: &mut Window,
19950        cx: &mut Context<Self>,
19951    ) {
19952        if let Some(path) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
19953            let project = self.project()?.read(cx);
19954            let path = buffer.read(cx).file()?.path();
19955            let path = path.display(project.path_style(cx));
19956            Some(path)
19957        }) {
19958            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
19959        } else {
19960            cx.propagate();
19961        }
19962    }
19963
19964    /// Returns the project path for the editor's buffer, if any buffer is
19965    /// opened in the editor.
19966    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
19967        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
19968            buffer.read(cx).project_path(cx)
19969        } else {
19970            None
19971        }
19972    }
19973
19974    // Returns true if the editor handled a go-to-line request
19975    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
19976        maybe!({
19977            let breakpoint_store = self.breakpoint_store.as_ref()?;
19978
19979            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
19980            else {
19981                self.clear_row_highlights::<ActiveDebugLine>();
19982                return None;
19983            };
19984
19985            let position = active_stack_frame.position;
19986            let buffer_id = position.buffer_id?;
19987            let snapshot = self
19988                .project
19989                .as_ref()?
19990                .read(cx)
19991                .buffer_for_id(buffer_id, cx)?
19992                .read(cx)
19993                .snapshot();
19994
19995            let mut handled = false;
19996            for (id, ExcerptRange { context, .. }) in
19997                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
19998            {
19999                if context.start.cmp(&position, &snapshot).is_ge()
20000                    || context.end.cmp(&position, &snapshot).is_lt()
20001                {
20002                    continue;
20003                }
20004                let snapshot = self.buffer.read(cx).snapshot(cx);
20005                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
20006
20007                handled = true;
20008                self.clear_row_highlights::<ActiveDebugLine>();
20009
20010                self.go_to_line::<ActiveDebugLine>(
20011                    multibuffer_anchor,
20012                    Some(cx.theme().colors().editor_debugger_active_line_background),
20013                    window,
20014                    cx,
20015                );
20016
20017                cx.notify();
20018            }
20019
20020            handled.then_some(())
20021        })
20022        .is_some()
20023    }
20024
20025    pub fn copy_file_name_without_extension(
20026        &mut self,
20027        _: &CopyFileNameWithoutExtension,
20028        _: &mut Window,
20029        cx: &mut Context<Self>,
20030    ) {
20031        if let Some(file) = self.target_file(cx)
20032            && let Some(file_stem) = file.path().file_stem()
20033        {
20034            cx.write_to_clipboard(ClipboardItem::new_string(file_stem.to_string()));
20035        }
20036    }
20037
20038    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
20039        if let Some(file) = self.target_file(cx)
20040            && let Some(name) = file.path().file_name()
20041        {
20042            cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
20043        }
20044    }
20045
20046    pub fn toggle_git_blame(
20047        &mut self,
20048        _: &::git::Blame,
20049        window: &mut Window,
20050        cx: &mut Context<Self>,
20051    ) {
20052        self.show_git_blame_gutter = !self.show_git_blame_gutter;
20053
20054        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
20055            self.start_git_blame(true, window, cx);
20056        }
20057
20058        cx.notify();
20059    }
20060
20061    pub fn toggle_git_blame_inline(
20062        &mut self,
20063        _: &ToggleGitBlameInline,
20064        window: &mut Window,
20065        cx: &mut Context<Self>,
20066    ) {
20067        self.toggle_git_blame_inline_internal(true, window, cx);
20068        cx.notify();
20069    }
20070
20071    pub fn open_git_blame_commit(
20072        &mut self,
20073        _: &OpenGitBlameCommit,
20074        window: &mut Window,
20075        cx: &mut Context<Self>,
20076    ) {
20077        self.open_git_blame_commit_internal(window, cx);
20078    }
20079
20080    fn open_git_blame_commit_internal(
20081        &mut self,
20082        window: &mut Window,
20083        cx: &mut Context<Self>,
20084    ) -> Option<()> {
20085        let blame = self.blame.as_ref()?;
20086        let snapshot = self.snapshot(window, cx);
20087        let cursor = self
20088            .selections
20089            .newest::<Point>(&snapshot.display_snapshot)
20090            .head();
20091        let (buffer, point, _) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)?;
20092        let (_, blame_entry) = blame
20093            .update(cx, |blame, cx| {
20094                blame
20095                    .blame_for_rows(
20096                        &[RowInfo {
20097                            buffer_id: Some(buffer.remote_id()),
20098                            buffer_row: Some(point.row),
20099                            ..Default::default()
20100                        }],
20101                        cx,
20102                    )
20103                    .next()
20104            })
20105            .flatten()?;
20106        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
20107        let repo = blame.read(cx).repository(cx, buffer.remote_id())?;
20108        let workspace = self.workspace()?.downgrade();
20109        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
20110        None
20111    }
20112
20113    pub fn git_blame_inline_enabled(&self) -> bool {
20114        self.git_blame_inline_enabled
20115    }
20116
20117    pub fn toggle_selection_menu(
20118        &mut self,
20119        _: &ToggleSelectionMenu,
20120        _: &mut Window,
20121        cx: &mut Context<Self>,
20122    ) {
20123        self.show_selection_menu = self
20124            .show_selection_menu
20125            .map(|show_selections_menu| !show_selections_menu)
20126            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
20127
20128        cx.notify();
20129    }
20130
20131    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
20132        self.show_selection_menu
20133            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
20134    }
20135
20136    fn start_git_blame(
20137        &mut self,
20138        user_triggered: bool,
20139        window: &mut Window,
20140        cx: &mut Context<Self>,
20141    ) {
20142        if let Some(project) = self.project() {
20143            if let Some(buffer) = self.buffer().read(cx).as_singleton()
20144                && buffer.read(cx).file().is_none()
20145            {
20146                return;
20147            }
20148
20149            let focused = self.focus_handle(cx).contains_focused(window, cx);
20150
20151            let project = project.clone();
20152            let blame = cx
20153                .new(|cx| GitBlame::new(self.buffer.clone(), project, user_triggered, focused, cx));
20154            self.blame_subscription =
20155                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
20156            self.blame = Some(blame);
20157        }
20158    }
20159
20160    fn toggle_git_blame_inline_internal(
20161        &mut self,
20162        user_triggered: bool,
20163        window: &mut Window,
20164        cx: &mut Context<Self>,
20165    ) {
20166        if self.git_blame_inline_enabled {
20167            self.git_blame_inline_enabled = false;
20168            self.show_git_blame_inline = false;
20169            self.show_git_blame_inline_delay_task.take();
20170        } else {
20171            self.git_blame_inline_enabled = true;
20172            self.start_git_blame_inline(user_triggered, window, cx);
20173        }
20174
20175        cx.notify();
20176    }
20177
20178    fn start_git_blame_inline(
20179        &mut self,
20180        user_triggered: bool,
20181        window: &mut Window,
20182        cx: &mut Context<Self>,
20183    ) {
20184        self.start_git_blame(user_triggered, window, cx);
20185
20186        if ProjectSettings::get_global(cx)
20187            .git
20188            .inline_blame_delay()
20189            .is_some()
20190        {
20191            self.start_inline_blame_timer(window, cx);
20192        } else {
20193            self.show_git_blame_inline = true
20194        }
20195    }
20196
20197    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
20198        self.blame.as_ref()
20199    }
20200
20201    pub fn show_git_blame_gutter(&self) -> bool {
20202        self.show_git_blame_gutter
20203    }
20204
20205    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
20206        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
20207    }
20208
20209    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
20210        self.show_git_blame_inline
20211            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
20212            && !self.newest_selection_head_on_empty_line(cx)
20213            && self.has_blame_entries(cx)
20214    }
20215
20216    fn has_blame_entries(&self, cx: &App) -> bool {
20217        self.blame()
20218            .is_some_and(|blame| blame.read(cx).has_generated_entries())
20219    }
20220
20221    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
20222        let cursor_anchor = self.selections.newest_anchor().head();
20223
20224        let snapshot = self.buffer.read(cx).snapshot(cx);
20225        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
20226
20227        snapshot.line_len(buffer_row) == 0
20228    }
20229
20230    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
20231        let buffer_and_selection = maybe!({
20232            let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
20233            let selection_range = selection.range();
20234
20235            let multi_buffer = self.buffer().read(cx);
20236            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
20237            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
20238
20239            let (buffer, range, _) = if selection.reversed {
20240                buffer_ranges.first()
20241            } else {
20242                buffer_ranges.last()
20243            }?;
20244
20245            let selection = text::ToPoint::to_point(&range.start, buffer).row
20246                ..text::ToPoint::to_point(&range.end, buffer).row;
20247            Some((multi_buffer.buffer(buffer.remote_id()).unwrap(), selection))
20248        });
20249
20250        let Some((buffer, selection)) = buffer_and_selection else {
20251            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
20252        };
20253
20254        let Some(project) = self.project() else {
20255            return Task::ready(Err(anyhow!("editor does not have project")));
20256        };
20257
20258        project.update(cx, |project, cx| {
20259            project.get_permalink_to_line(&buffer, selection, cx)
20260        })
20261    }
20262
20263    pub fn copy_permalink_to_line(
20264        &mut self,
20265        _: &CopyPermalinkToLine,
20266        window: &mut Window,
20267        cx: &mut Context<Self>,
20268    ) {
20269        let permalink_task = self.get_permalink_to_line(cx);
20270        let workspace = self.workspace();
20271
20272        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
20273            Ok(permalink) => {
20274                cx.update(|_, cx| {
20275                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
20276                })
20277                .ok();
20278            }
20279            Err(err) => {
20280                let message = format!("Failed to copy permalink: {err}");
20281
20282                anyhow::Result::<()>::Err(err).log_err();
20283
20284                if let Some(workspace) = workspace {
20285                    workspace
20286                        .update_in(cx, |workspace, _, cx| {
20287                            struct CopyPermalinkToLine;
20288
20289                            workspace.show_toast(
20290                                Toast::new(
20291                                    NotificationId::unique::<CopyPermalinkToLine>(),
20292                                    message,
20293                                ),
20294                                cx,
20295                            )
20296                        })
20297                        .ok();
20298                }
20299            }
20300        })
20301        .detach();
20302    }
20303
20304    pub fn copy_file_location(
20305        &mut self,
20306        _: &CopyFileLocation,
20307        _: &mut Window,
20308        cx: &mut Context<Self>,
20309    ) {
20310        let selection = self
20311            .selections
20312            .newest::<Point>(&self.display_snapshot(cx))
20313            .start
20314            .row
20315            + 1;
20316        if let Some(file) = self.target_file(cx) {
20317            let path = file.path().display(file.path_style(cx));
20318            cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
20319        }
20320    }
20321
20322    pub fn open_permalink_to_line(
20323        &mut self,
20324        _: &OpenPermalinkToLine,
20325        window: &mut Window,
20326        cx: &mut Context<Self>,
20327    ) {
20328        let permalink_task = self.get_permalink_to_line(cx);
20329        let workspace = self.workspace();
20330
20331        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
20332            Ok(permalink) => {
20333                cx.update(|_, cx| {
20334                    cx.open_url(permalink.as_ref());
20335                })
20336                .ok();
20337            }
20338            Err(err) => {
20339                let message = format!("Failed to open permalink: {err}");
20340
20341                anyhow::Result::<()>::Err(err).log_err();
20342
20343                if let Some(workspace) = workspace {
20344                    workspace
20345                        .update(cx, |workspace, cx| {
20346                            struct OpenPermalinkToLine;
20347
20348                            workspace.show_toast(
20349                                Toast::new(
20350                                    NotificationId::unique::<OpenPermalinkToLine>(),
20351                                    message,
20352                                ),
20353                                cx,
20354                            )
20355                        })
20356                        .ok();
20357                }
20358            }
20359        })
20360        .detach();
20361    }
20362
20363    pub fn insert_uuid_v4(
20364        &mut self,
20365        _: &InsertUuidV4,
20366        window: &mut Window,
20367        cx: &mut Context<Self>,
20368    ) {
20369        self.insert_uuid(UuidVersion::V4, window, cx);
20370    }
20371
20372    pub fn insert_uuid_v7(
20373        &mut self,
20374        _: &InsertUuidV7,
20375        window: &mut Window,
20376        cx: &mut Context<Self>,
20377    ) {
20378        self.insert_uuid(UuidVersion::V7, window, cx);
20379    }
20380
20381    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
20382        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
20383        self.transact(window, cx, |this, window, cx| {
20384            let edits = this
20385                .selections
20386                .all::<Point>(&this.display_snapshot(cx))
20387                .into_iter()
20388                .map(|selection| {
20389                    let uuid = match version {
20390                        UuidVersion::V4 => uuid::Uuid::new_v4(),
20391                        UuidVersion::V7 => uuid::Uuid::now_v7(),
20392                    };
20393
20394                    (selection.range(), uuid.to_string())
20395                });
20396            this.edit(edits, cx);
20397            this.refresh_edit_prediction(true, false, window, cx);
20398        });
20399    }
20400
20401    pub fn open_selections_in_multibuffer(
20402        &mut self,
20403        _: &OpenSelectionsInMultibuffer,
20404        window: &mut Window,
20405        cx: &mut Context<Self>,
20406    ) {
20407        let multibuffer = self.buffer.read(cx);
20408
20409        let Some(buffer) = multibuffer.as_singleton() else {
20410            return;
20411        };
20412
20413        let Some(workspace) = self.workspace() else {
20414            return;
20415        };
20416
20417        let title = multibuffer.title(cx).to_string();
20418
20419        let locations = self
20420            .selections
20421            .all_anchors(&self.display_snapshot(cx))
20422            .iter()
20423            .map(|selection| {
20424                (
20425                    buffer.clone(),
20426                    (selection.start.text_anchor..selection.end.text_anchor)
20427                        .to_point(buffer.read(cx)),
20428                )
20429            })
20430            .into_group_map();
20431
20432        cx.spawn_in(window, async move |_, cx| {
20433            workspace.update_in(cx, |workspace, window, cx| {
20434                Self::open_locations_in_multibuffer(
20435                    workspace,
20436                    locations,
20437                    format!("Selections for '{title}'"),
20438                    false,
20439                    MultibufferSelectionMode::All,
20440                    window,
20441                    cx,
20442                );
20443            })
20444        })
20445        .detach();
20446    }
20447
20448    /// Adds a row highlight for the given range. If a row has multiple highlights, the
20449    /// last highlight added will be used.
20450    ///
20451    /// If the range ends at the beginning of a line, then that line will not be highlighted.
20452    pub fn highlight_rows<T: 'static>(
20453        &mut self,
20454        range: Range<Anchor>,
20455        color: Hsla,
20456        options: RowHighlightOptions,
20457        cx: &mut Context<Self>,
20458    ) {
20459        let snapshot = self.buffer().read(cx).snapshot(cx);
20460        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
20461        let ix = row_highlights.binary_search_by(|highlight| {
20462            Ordering::Equal
20463                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
20464                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
20465        });
20466
20467        if let Err(mut ix) = ix {
20468            let index = post_inc(&mut self.highlight_order);
20469
20470            // If this range intersects with the preceding highlight, then merge it with
20471            // the preceding highlight. Otherwise insert a new highlight.
20472            let mut merged = false;
20473            if ix > 0 {
20474                let prev_highlight = &mut row_highlights[ix - 1];
20475                if prev_highlight
20476                    .range
20477                    .end
20478                    .cmp(&range.start, &snapshot)
20479                    .is_ge()
20480                {
20481                    ix -= 1;
20482                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
20483                        prev_highlight.range.end = range.end;
20484                    }
20485                    merged = true;
20486                    prev_highlight.index = index;
20487                    prev_highlight.color = color;
20488                    prev_highlight.options = options;
20489                }
20490            }
20491
20492            if !merged {
20493                row_highlights.insert(
20494                    ix,
20495                    RowHighlight {
20496                        range,
20497                        index,
20498                        color,
20499                        options,
20500                        type_id: TypeId::of::<T>(),
20501                    },
20502                );
20503            }
20504
20505            // If any of the following highlights intersect with this one, merge them.
20506            while let Some(next_highlight) = row_highlights.get(ix + 1) {
20507                let highlight = &row_highlights[ix];
20508                if next_highlight
20509                    .range
20510                    .start
20511                    .cmp(&highlight.range.end, &snapshot)
20512                    .is_le()
20513                {
20514                    if next_highlight
20515                        .range
20516                        .end
20517                        .cmp(&highlight.range.end, &snapshot)
20518                        .is_gt()
20519                    {
20520                        row_highlights[ix].range.end = next_highlight.range.end;
20521                    }
20522                    row_highlights.remove(ix + 1);
20523                } else {
20524                    break;
20525                }
20526            }
20527        }
20528    }
20529
20530    /// Remove any highlighted row ranges of the given type that intersect the
20531    /// given ranges.
20532    pub fn remove_highlighted_rows<T: 'static>(
20533        &mut self,
20534        ranges_to_remove: Vec<Range<Anchor>>,
20535        cx: &mut Context<Self>,
20536    ) {
20537        let snapshot = self.buffer().read(cx).snapshot(cx);
20538        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
20539        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
20540        row_highlights.retain(|highlight| {
20541            while let Some(range_to_remove) = ranges_to_remove.peek() {
20542                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
20543                    Ordering::Less | Ordering::Equal => {
20544                        ranges_to_remove.next();
20545                    }
20546                    Ordering::Greater => {
20547                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
20548                            Ordering::Less | Ordering::Equal => {
20549                                return false;
20550                            }
20551                            Ordering::Greater => break,
20552                        }
20553                    }
20554                }
20555            }
20556
20557            true
20558        })
20559    }
20560
20561    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
20562    pub fn clear_row_highlights<T: 'static>(&mut self) {
20563        self.highlighted_rows.remove(&TypeId::of::<T>());
20564    }
20565
20566    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
20567    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
20568        self.highlighted_rows
20569            .get(&TypeId::of::<T>())
20570            .map_or(&[] as &[_], |vec| vec.as_slice())
20571            .iter()
20572            .map(|highlight| (highlight.range.clone(), highlight.color))
20573    }
20574
20575    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
20576    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
20577    /// Allows to ignore certain kinds of highlights.
20578    pub fn highlighted_display_rows(
20579        &self,
20580        window: &mut Window,
20581        cx: &mut App,
20582    ) -> BTreeMap<DisplayRow, LineHighlight> {
20583        let snapshot = self.snapshot(window, cx);
20584        let mut used_highlight_orders = HashMap::default();
20585        self.highlighted_rows
20586            .iter()
20587            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
20588            .fold(
20589                BTreeMap::<DisplayRow, LineHighlight>::new(),
20590                |mut unique_rows, highlight| {
20591                    let start = highlight.range.start.to_display_point(&snapshot);
20592                    let end = highlight.range.end.to_display_point(&snapshot);
20593                    let start_row = start.row().0;
20594                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
20595                        && end.column() == 0
20596                    {
20597                        end.row().0.saturating_sub(1)
20598                    } else {
20599                        end.row().0
20600                    };
20601                    for row in start_row..=end_row {
20602                        let used_index =
20603                            used_highlight_orders.entry(row).or_insert(highlight.index);
20604                        if highlight.index >= *used_index {
20605                            *used_index = highlight.index;
20606                            unique_rows.insert(
20607                                DisplayRow(row),
20608                                LineHighlight {
20609                                    include_gutter: highlight.options.include_gutter,
20610                                    border: None,
20611                                    background: highlight.color.into(),
20612                                    type_id: Some(highlight.type_id),
20613                                },
20614                            );
20615                        }
20616                    }
20617                    unique_rows
20618                },
20619            )
20620    }
20621
20622    pub fn highlighted_display_row_for_autoscroll(
20623        &self,
20624        snapshot: &DisplaySnapshot,
20625    ) -> Option<DisplayRow> {
20626        self.highlighted_rows
20627            .values()
20628            .flat_map(|highlighted_rows| highlighted_rows.iter())
20629            .filter_map(|highlight| {
20630                if highlight.options.autoscroll {
20631                    Some(highlight.range.start.to_display_point(snapshot).row())
20632                } else {
20633                    None
20634                }
20635            })
20636            .min()
20637    }
20638
20639    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
20640        self.highlight_background::<SearchWithinRange>(
20641            ranges,
20642            |colors| colors.colors().editor_document_highlight_read_background,
20643            cx,
20644        )
20645    }
20646
20647    pub fn set_breadcrumb_header(&mut self, new_header: String) {
20648        self.breadcrumb_header = Some(new_header);
20649    }
20650
20651    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
20652        self.clear_background_highlights::<SearchWithinRange>(cx);
20653    }
20654
20655    pub fn highlight_background<T: 'static>(
20656        &mut self,
20657        ranges: &[Range<Anchor>],
20658        color_fetcher: fn(&Theme) -> Hsla,
20659        cx: &mut Context<Self>,
20660    ) {
20661        self.background_highlights.insert(
20662            HighlightKey::Type(TypeId::of::<T>()),
20663            (color_fetcher, Arc::from(ranges)),
20664        );
20665        self.scrollbar_marker_state.dirty = true;
20666        cx.notify();
20667    }
20668
20669    pub fn highlight_background_key<T: 'static>(
20670        &mut self,
20671        key: usize,
20672        ranges: &[Range<Anchor>],
20673        color_fetcher: fn(&Theme) -> Hsla,
20674        cx: &mut Context<Self>,
20675    ) {
20676        self.background_highlights.insert(
20677            HighlightKey::TypePlus(TypeId::of::<T>(), key),
20678            (color_fetcher, Arc::from(ranges)),
20679        );
20680        self.scrollbar_marker_state.dirty = true;
20681        cx.notify();
20682    }
20683
20684    pub fn clear_background_highlights<T: 'static>(
20685        &mut self,
20686        cx: &mut Context<Self>,
20687    ) -> Option<BackgroundHighlight> {
20688        let text_highlights = self
20689            .background_highlights
20690            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
20691        if !text_highlights.1.is_empty() {
20692            self.scrollbar_marker_state.dirty = true;
20693            cx.notify();
20694        }
20695        Some(text_highlights)
20696    }
20697
20698    pub fn highlight_gutter<T: 'static>(
20699        &mut self,
20700        ranges: impl Into<Vec<Range<Anchor>>>,
20701        color_fetcher: fn(&App) -> Hsla,
20702        cx: &mut Context<Self>,
20703    ) {
20704        self.gutter_highlights
20705            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
20706        cx.notify();
20707    }
20708
20709    pub fn clear_gutter_highlights<T: 'static>(
20710        &mut self,
20711        cx: &mut Context<Self>,
20712    ) -> Option<GutterHighlight> {
20713        cx.notify();
20714        self.gutter_highlights.remove(&TypeId::of::<T>())
20715    }
20716
20717    pub fn insert_gutter_highlight<T: 'static>(
20718        &mut self,
20719        range: Range<Anchor>,
20720        color_fetcher: fn(&App) -> Hsla,
20721        cx: &mut Context<Self>,
20722    ) {
20723        let snapshot = self.buffer().read(cx).snapshot(cx);
20724        let mut highlights = self
20725            .gutter_highlights
20726            .remove(&TypeId::of::<T>())
20727            .map(|(_, highlights)| highlights)
20728            .unwrap_or_default();
20729        let ix = highlights.binary_search_by(|highlight| {
20730            Ordering::Equal
20731                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
20732                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
20733        });
20734        if let Err(ix) = ix {
20735            highlights.insert(ix, range);
20736        }
20737        self.gutter_highlights
20738            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
20739    }
20740
20741    pub fn remove_gutter_highlights<T: 'static>(
20742        &mut self,
20743        ranges_to_remove: Vec<Range<Anchor>>,
20744        cx: &mut Context<Self>,
20745    ) {
20746        let snapshot = self.buffer().read(cx).snapshot(cx);
20747        let Some((color_fetcher, mut gutter_highlights)) =
20748            self.gutter_highlights.remove(&TypeId::of::<T>())
20749        else {
20750            return;
20751        };
20752        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
20753        gutter_highlights.retain(|highlight| {
20754            while let Some(range_to_remove) = ranges_to_remove.peek() {
20755                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
20756                    Ordering::Less | Ordering::Equal => {
20757                        ranges_to_remove.next();
20758                    }
20759                    Ordering::Greater => {
20760                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
20761                            Ordering::Less | Ordering::Equal => {
20762                                return false;
20763                            }
20764                            Ordering::Greater => break,
20765                        }
20766                    }
20767                }
20768            }
20769
20770            true
20771        });
20772        self.gutter_highlights
20773            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
20774    }
20775
20776    #[cfg(feature = "test-support")]
20777    pub fn all_text_highlights(
20778        &self,
20779        window: &mut Window,
20780        cx: &mut Context<Self>,
20781    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
20782        let snapshot = self.snapshot(window, cx);
20783        self.display_map.update(cx, |display_map, _| {
20784            display_map
20785                .all_text_highlights()
20786                .map(|highlight| {
20787                    let (style, ranges) = highlight.as_ref();
20788                    (
20789                        *style,
20790                        ranges
20791                            .iter()
20792                            .map(|range| range.clone().to_display_points(&snapshot))
20793                            .collect(),
20794                    )
20795                })
20796                .collect()
20797        })
20798    }
20799
20800    #[cfg(feature = "test-support")]
20801    pub fn all_text_background_highlights(
20802        &self,
20803        window: &mut Window,
20804        cx: &mut Context<Self>,
20805    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20806        let snapshot = self.snapshot(window, cx);
20807        let buffer = &snapshot.buffer_snapshot();
20808        let start = buffer.anchor_before(0);
20809        let end = buffer.anchor_after(buffer.len());
20810        self.sorted_background_highlights_in_range(start..end, &snapshot, cx.theme())
20811    }
20812
20813    #[cfg(any(test, feature = "test-support"))]
20814    pub fn sorted_background_highlights_in_range(
20815        &self,
20816        search_range: Range<Anchor>,
20817        display_snapshot: &DisplaySnapshot,
20818        theme: &Theme,
20819    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20820        let mut res = self.background_highlights_in_range(search_range, display_snapshot, theme);
20821        res.sort_by(|a, b| {
20822            a.0.start
20823                .cmp(&b.0.start)
20824                .then_with(|| a.0.end.cmp(&b.0.end))
20825                .then_with(|| a.1.cmp(&b.1))
20826        });
20827        res
20828    }
20829
20830    #[cfg(feature = "test-support")]
20831    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
20832        let snapshot = self.buffer().read(cx).snapshot(cx);
20833
20834        let highlights = self
20835            .background_highlights
20836            .get(&HighlightKey::Type(TypeId::of::<
20837                items::BufferSearchHighlights,
20838            >()));
20839
20840        if let Some((_color, ranges)) = highlights {
20841            ranges
20842                .iter()
20843                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
20844                .collect_vec()
20845        } else {
20846            vec![]
20847        }
20848    }
20849
20850    fn document_highlights_for_position<'a>(
20851        &'a self,
20852        position: Anchor,
20853        buffer: &'a MultiBufferSnapshot,
20854    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
20855        let read_highlights = self
20856            .background_highlights
20857            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
20858            .map(|h| &h.1);
20859        let write_highlights = self
20860            .background_highlights
20861            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
20862            .map(|h| &h.1);
20863        let left_position = position.bias_left(buffer);
20864        let right_position = position.bias_right(buffer);
20865        read_highlights
20866            .into_iter()
20867            .chain(write_highlights)
20868            .flat_map(move |ranges| {
20869                let start_ix = match ranges.binary_search_by(|probe| {
20870                    let cmp = probe.end.cmp(&left_position, buffer);
20871                    if cmp.is_ge() {
20872                        Ordering::Greater
20873                    } else {
20874                        Ordering::Less
20875                    }
20876                }) {
20877                    Ok(i) | Err(i) => i,
20878                };
20879
20880                ranges[start_ix..]
20881                    .iter()
20882                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
20883            })
20884    }
20885
20886    pub fn has_background_highlights<T: 'static>(&self) -> bool {
20887        self.background_highlights
20888            .get(&HighlightKey::Type(TypeId::of::<T>()))
20889            .is_some_and(|(_, highlights)| !highlights.is_empty())
20890    }
20891
20892    /// Returns all background highlights for a given range.
20893    ///
20894    /// The order of highlights is not deterministic, do sort the ranges if needed for the logic.
20895    pub fn background_highlights_in_range(
20896        &self,
20897        search_range: Range<Anchor>,
20898        display_snapshot: &DisplaySnapshot,
20899        theme: &Theme,
20900    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20901        let mut results = Vec::new();
20902        for (color_fetcher, ranges) in self.background_highlights.values() {
20903            let color = color_fetcher(theme);
20904            let start_ix = match ranges.binary_search_by(|probe| {
20905                let cmp = probe
20906                    .end
20907                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
20908                if cmp.is_gt() {
20909                    Ordering::Greater
20910                } else {
20911                    Ordering::Less
20912                }
20913            }) {
20914                Ok(i) | Err(i) => i,
20915            };
20916            for range in &ranges[start_ix..] {
20917                if range
20918                    .start
20919                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
20920                    .is_ge()
20921                {
20922                    break;
20923                }
20924
20925                let start = range.start.to_display_point(display_snapshot);
20926                let end = range.end.to_display_point(display_snapshot);
20927                results.push((start..end, color))
20928            }
20929        }
20930        results
20931    }
20932
20933    pub fn gutter_highlights_in_range(
20934        &self,
20935        search_range: Range<Anchor>,
20936        display_snapshot: &DisplaySnapshot,
20937        cx: &App,
20938    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20939        let mut results = Vec::new();
20940        for (color_fetcher, ranges) in self.gutter_highlights.values() {
20941            let color = color_fetcher(cx);
20942            let start_ix = match ranges.binary_search_by(|probe| {
20943                let cmp = probe
20944                    .end
20945                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
20946                if cmp.is_gt() {
20947                    Ordering::Greater
20948                } else {
20949                    Ordering::Less
20950                }
20951            }) {
20952                Ok(i) | Err(i) => i,
20953            };
20954            for range in &ranges[start_ix..] {
20955                if range
20956                    .start
20957                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
20958                    .is_ge()
20959                {
20960                    break;
20961                }
20962
20963                let start = range.start.to_display_point(display_snapshot);
20964                let end = range.end.to_display_point(display_snapshot);
20965                results.push((start..end, color))
20966            }
20967        }
20968        results
20969    }
20970
20971    /// Get the text ranges corresponding to the redaction query
20972    pub fn redacted_ranges(
20973        &self,
20974        search_range: Range<Anchor>,
20975        display_snapshot: &DisplaySnapshot,
20976        cx: &App,
20977    ) -> Vec<Range<DisplayPoint>> {
20978        display_snapshot
20979            .buffer_snapshot()
20980            .redacted_ranges(search_range, |file| {
20981                if let Some(file) = file {
20982                    file.is_private()
20983                        && EditorSettings::get(
20984                            Some(SettingsLocation {
20985                                worktree_id: file.worktree_id(cx),
20986                                path: file.path().as_ref(),
20987                            }),
20988                            cx,
20989                        )
20990                        .redact_private_values
20991                } else {
20992                    false
20993                }
20994            })
20995            .map(|range| {
20996                range.start.to_display_point(display_snapshot)
20997                    ..range.end.to_display_point(display_snapshot)
20998            })
20999            .collect()
21000    }
21001
21002    pub fn highlight_text_key<T: 'static>(
21003        &mut self,
21004        key: usize,
21005        ranges: Vec<Range<Anchor>>,
21006        style: HighlightStyle,
21007        cx: &mut Context<Self>,
21008    ) {
21009        self.display_map.update(cx, |map, _| {
21010            map.highlight_text(
21011                HighlightKey::TypePlus(TypeId::of::<T>(), key),
21012                ranges,
21013                style,
21014            );
21015        });
21016        cx.notify();
21017    }
21018
21019    pub fn highlight_text<T: 'static>(
21020        &mut self,
21021        ranges: Vec<Range<Anchor>>,
21022        style: HighlightStyle,
21023        cx: &mut Context<Self>,
21024    ) {
21025        self.display_map.update(cx, |map, _| {
21026            map.highlight_text(HighlightKey::Type(TypeId::of::<T>()), ranges, style)
21027        });
21028        cx.notify();
21029    }
21030
21031    pub fn text_highlights<'a, T: 'static>(
21032        &'a self,
21033        cx: &'a App,
21034    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
21035        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
21036    }
21037
21038    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
21039        let cleared = self
21040            .display_map
21041            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
21042        if cleared {
21043            cx.notify();
21044        }
21045    }
21046
21047    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
21048        (self.read_only(cx) || self.blink_manager.read(cx).visible())
21049            && self.focus_handle.is_focused(window)
21050    }
21051
21052    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
21053        self.show_cursor_when_unfocused = is_enabled;
21054        cx.notify();
21055    }
21056
21057    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
21058        cx.notify();
21059    }
21060
21061    fn on_debug_session_event(
21062        &mut self,
21063        _session: Entity<Session>,
21064        event: &SessionEvent,
21065        cx: &mut Context<Self>,
21066    ) {
21067        if let SessionEvent::InvalidateInlineValue = event {
21068            self.refresh_inline_values(cx);
21069        }
21070    }
21071
21072    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
21073        let Some(project) = self.project.clone() else {
21074            return;
21075        };
21076
21077        if !self.inline_value_cache.enabled {
21078            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
21079            self.splice_inlays(&inlays, Vec::new(), cx);
21080            return;
21081        }
21082
21083        let current_execution_position = self
21084            .highlighted_rows
21085            .get(&TypeId::of::<ActiveDebugLine>())
21086            .and_then(|lines| lines.last().map(|line| line.range.end));
21087
21088        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
21089            let inline_values = editor
21090                .update(cx, |editor, cx| {
21091                    let Some(current_execution_position) = current_execution_position else {
21092                        return Some(Task::ready(Ok(Vec::new())));
21093                    };
21094
21095                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
21096                        let snapshot = buffer.snapshot(cx);
21097
21098                        let excerpt = snapshot.excerpt_containing(
21099                            current_execution_position..current_execution_position,
21100                        )?;
21101
21102                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
21103                    })?;
21104
21105                    let range =
21106                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
21107
21108                    project.inline_values(buffer, range, cx)
21109                })
21110                .ok()
21111                .flatten()?
21112                .await
21113                .context("refreshing debugger inlays")
21114                .log_err()?;
21115
21116            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
21117
21118            for (buffer_id, inline_value) in inline_values
21119                .into_iter()
21120                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
21121            {
21122                buffer_inline_values
21123                    .entry(buffer_id)
21124                    .or_default()
21125                    .push(inline_value);
21126            }
21127
21128            editor
21129                .update(cx, |editor, cx| {
21130                    let snapshot = editor.buffer.read(cx).snapshot(cx);
21131                    let mut new_inlays = Vec::default();
21132
21133                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
21134                        let buffer_id = buffer_snapshot.remote_id();
21135                        buffer_inline_values
21136                            .get(&buffer_id)
21137                            .into_iter()
21138                            .flatten()
21139                            .for_each(|hint| {
21140                                let inlay = Inlay::debugger(
21141                                    post_inc(&mut editor.next_inlay_id),
21142                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
21143                                    hint.text(),
21144                                );
21145                                if !inlay.text().chars().contains(&'\n') {
21146                                    new_inlays.push(inlay);
21147                                }
21148                            });
21149                    }
21150
21151                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
21152                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
21153
21154                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
21155                })
21156                .ok()?;
21157            Some(())
21158        });
21159    }
21160
21161    fn on_buffer_event(
21162        &mut self,
21163        multibuffer: &Entity<MultiBuffer>,
21164        event: &multi_buffer::Event,
21165        window: &mut Window,
21166        cx: &mut Context<Self>,
21167    ) {
21168        match event {
21169            multi_buffer::Event::Edited { edited_buffer } => {
21170                self.scrollbar_marker_state.dirty = true;
21171                self.active_indent_guides_state.dirty = true;
21172                self.refresh_active_diagnostics(cx);
21173                self.refresh_code_actions(window, cx);
21174                self.refresh_selected_text_highlights(true, window, cx);
21175                self.refresh_single_line_folds(window, cx);
21176                self.refresh_matching_bracket_highlights(window, cx);
21177                if self.has_active_edit_prediction() {
21178                    self.update_visible_edit_prediction(window, cx);
21179                }
21180
21181                if let Some(buffer) = edited_buffer {
21182                    if buffer.read(cx).file().is_none() {
21183                        cx.emit(EditorEvent::TitleChanged);
21184                    }
21185
21186                    if self.project.is_some() {
21187                        let buffer_id = buffer.read(cx).remote_id();
21188                        self.register_buffer(buffer_id, cx);
21189                        self.update_lsp_data(Some(buffer_id), window, cx);
21190                        self.refresh_inlay_hints(
21191                            InlayHintRefreshReason::BufferEdited(buffer_id),
21192                            cx,
21193                        );
21194                    }
21195                }
21196
21197                cx.emit(EditorEvent::BufferEdited);
21198                cx.emit(SearchEvent::MatchesInvalidated);
21199
21200                let Some(project) = &self.project else { return };
21201                let (telemetry, is_via_ssh) = {
21202                    let project = project.read(cx);
21203                    let telemetry = project.client().telemetry().clone();
21204                    let is_via_ssh = project.is_via_remote_server();
21205                    (telemetry, is_via_ssh)
21206                };
21207                telemetry.log_edit_event("editor", is_via_ssh);
21208            }
21209            multi_buffer::Event::ExcerptsAdded {
21210                buffer,
21211                predecessor,
21212                excerpts,
21213            } => {
21214                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21215                let buffer_id = buffer.read(cx).remote_id();
21216                if self.buffer.read(cx).diff_for(buffer_id).is_none()
21217                    && let Some(project) = &self.project
21218                {
21219                    update_uncommitted_diff_for_buffer(
21220                        cx.entity(),
21221                        project,
21222                        [buffer.clone()],
21223                        self.buffer.clone(),
21224                        cx,
21225                    )
21226                    .detach();
21227                }
21228                self.update_lsp_data(Some(buffer_id), window, cx);
21229                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
21230                cx.emit(EditorEvent::ExcerptsAdded {
21231                    buffer: buffer.clone(),
21232                    predecessor: *predecessor,
21233                    excerpts: excerpts.clone(),
21234                });
21235            }
21236            multi_buffer::Event::ExcerptsRemoved {
21237                ids,
21238                removed_buffer_ids,
21239            } => {
21240                if let Some(inlay_hints) = &mut self.inlay_hints {
21241                    inlay_hints.remove_inlay_chunk_data(removed_buffer_ids);
21242                }
21243                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
21244                for buffer_id in removed_buffer_ids {
21245                    self.registered_buffers.remove(buffer_id);
21246                }
21247                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
21248                cx.emit(EditorEvent::ExcerptsRemoved {
21249                    ids: ids.clone(),
21250                    removed_buffer_ids: removed_buffer_ids.clone(),
21251                });
21252            }
21253            multi_buffer::Event::ExcerptsEdited {
21254                excerpt_ids,
21255                buffer_ids,
21256            } => {
21257                self.display_map.update(cx, |map, cx| {
21258                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
21259                });
21260                cx.emit(EditorEvent::ExcerptsEdited {
21261                    ids: excerpt_ids.clone(),
21262                });
21263            }
21264            multi_buffer::Event::ExcerptsExpanded { ids } => {
21265                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
21266                self.refresh_document_highlights(cx);
21267                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
21268            }
21269            multi_buffer::Event::Reparsed(buffer_id) => {
21270                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21271                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
21272
21273                cx.emit(EditorEvent::Reparsed(*buffer_id));
21274            }
21275            multi_buffer::Event::DiffHunksToggled => {
21276                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21277            }
21278            multi_buffer::Event::LanguageChanged(buffer_id) => {
21279                self.registered_buffers.remove(&buffer_id);
21280                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
21281                cx.emit(EditorEvent::Reparsed(*buffer_id));
21282                cx.notify();
21283            }
21284            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
21285            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
21286            multi_buffer::Event::FileHandleChanged
21287            | multi_buffer::Event::Reloaded
21288            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
21289            multi_buffer::Event::DiagnosticsUpdated => {
21290                self.update_diagnostics_state(window, cx);
21291            }
21292            _ => {}
21293        };
21294    }
21295
21296    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
21297        if !self.diagnostics_enabled() {
21298            return;
21299        }
21300        self.refresh_active_diagnostics(cx);
21301        self.refresh_inline_diagnostics(true, window, cx);
21302        self.scrollbar_marker_state.dirty = true;
21303        cx.notify();
21304    }
21305
21306    pub fn start_temporary_diff_override(&mut self) {
21307        self.load_diff_task.take();
21308        self.temporary_diff_override = true;
21309    }
21310
21311    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
21312        self.temporary_diff_override = false;
21313        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
21314        self.buffer.update(cx, |buffer, cx| {
21315            buffer.set_all_diff_hunks_collapsed(cx);
21316        });
21317
21318        if let Some(project) = self.project.clone() {
21319            self.load_diff_task = Some(
21320                update_uncommitted_diff_for_buffer(
21321                    cx.entity(),
21322                    &project,
21323                    self.buffer.read(cx).all_buffers(),
21324                    self.buffer.clone(),
21325                    cx,
21326                )
21327                .shared(),
21328            );
21329        }
21330    }
21331
21332    fn on_display_map_changed(
21333        &mut self,
21334        _: Entity<DisplayMap>,
21335        _: &mut Window,
21336        cx: &mut Context<Self>,
21337    ) {
21338        cx.notify();
21339    }
21340
21341    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21342        if self.diagnostics_enabled() {
21343            let new_severity = EditorSettings::get_global(cx)
21344                .diagnostics_max_severity
21345                .unwrap_or(DiagnosticSeverity::Hint);
21346            self.set_max_diagnostics_severity(new_severity, cx);
21347        }
21348        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21349        self.update_edit_prediction_settings(cx);
21350        self.refresh_edit_prediction(true, false, window, cx);
21351        self.refresh_inline_values(cx);
21352        self.refresh_inlay_hints(
21353            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
21354                self.selections.newest_anchor().head(),
21355                &self.buffer.read(cx).snapshot(cx),
21356                cx,
21357            )),
21358            cx,
21359        );
21360
21361        let old_cursor_shape = self.cursor_shape;
21362        let old_show_breadcrumbs = self.show_breadcrumbs;
21363
21364        {
21365            let editor_settings = EditorSettings::get_global(cx);
21366            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
21367            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
21368            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
21369            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
21370        }
21371
21372        if old_cursor_shape != self.cursor_shape {
21373            cx.emit(EditorEvent::CursorShapeChanged);
21374        }
21375
21376        if old_show_breadcrumbs != self.show_breadcrumbs {
21377            cx.emit(EditorEvent::BreadcrumbsChanged);
21378        }
21379
21380        let project_settings = ProjectSettings::get_global(cx);
21381        self.buffer_serialization = self
21382            .should_serialize_buffer()
21383            .then(|| BufferSerialization::new(project_settings.session.restore_unsaved_buffers));
21384
21385        if self.mode.is_full() {
21386            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
21387            let inline_blame_enabled = project_settings.git.inline_blame.enabled;
21388            if self.show_inline_diagnostics != show_inline_diagnostics {
21389                self.show_inline_diagnostics = show_inline_diagnostics;
21390                self.refresh_inline_diagnostics(false, window, cx);
21391            }
21392
21393            if self.git_blame_inline_enabled != inline_blame_enabled {
21394                self.toggle_git_blame_inline_internal(false, window, cx);
21395            }
21396
21397            let minimap_settings = EditorSettings::get_global(cx).minimap;
21398            if self.minimap_visibility != MinimapVisibility::Disabled {
21399                if self.minimap_visibility.settings_visibility()
21400                    != minimap_settings.minimap_enabled()
21401                {
21402                    self.set_minimap_visibility(
21403                        MinimapVisibility::for_mode(self.mode(), cx),
21404                        window,
21405                        cx,
21406                    );
21407                } else if let Some(minimap_entity) = self.minimap.as_ref() {
21408                    minimap_entity.update(cx, |minimap_editor, cx| {
21409                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
21410                    })
21411                }
21412            }
21413        }
21414
21415        if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
21416            colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
21417        }) {
21418            if !inlay_splice.is_empty() {
21419                self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
21420            }
21421            self.refresh_colors_for_visible_range(None, window, cx);
21422        }
21423
21424        cx.notify();
21425    }
21426
21427    pub fn set_searchable(&mut self, searchable: bool) {
21428        self.searchable = searchable;
21429    }
21430
21431    pub fn searchable(&self) -> bool {
21432        self.searchable
21433    }
21434
21435    pub fn open_excerpts_in_split(
21436        &mut self,
21437        _: &OpenExcerptsSplit,
21438        window: &mut Window,
21439        cx: &mut Context<Self>,
21440    ) {
21441        self.open_excerpts_common(None, true, window, cx)
21442    }
21443
21444    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
21445        self.open_excerpts_common(None, false, window, cx)
21446    }
21447
21448    fn open_excerpts_common(
21449        &mut self,
21450        jump_data: Option<JumpData>,
21451        split: bool,
21452        window: &mut Window,
21453        cx: &mut Context<Self>,
21454    ) {
21455        let Some(workspace) = self.workspace() else {
21456            cx.propagate();
21457            return;
21458        };
21459
21460        if self.buffer.read(cx).is_singleton() {
21461            cx.propagate();
21462            return;
21463        }
21464
21465        let mut new_selections_by_buffer = HashMap::default();
21466        match &jump_data {
21467            Some(JumpData::MultiBufferPoint {
21468                excerpt_id,
21469                position,
21470                anchor,
21471                line_offset_from_top,
21472            }) => {
21473                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
21474                if let Some(buffer) = multi_buffer_snapshot
21475                    .buffer_id_for_excerpt(*excerpt_id)
21476                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
21477                {
21478                    let buffer_snapshot = buffer.read(cx).snapshot();
21479                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
21480                        language::ToPoint::to_point(anchor, &buffer_snapshot)
21481                    } else {
21482                        buffer_snapshot.clip_point(*position, Bias::Left)
21483                    };
21484                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
21485                    new_selections_by_buffer.insert(
21486                        buffer,
21487                        (
21488                            vec![jump_to_offset..jump_to_offset],
21489                            Some(*line_offset_from_top),
21490                        ),
21491                    );
21492                }
21493            }
21494            Some(JumpData::MultiBufferRow {
21495                row,
21496                line_offset_from_top,
21497            }) => {
21498                let point = MultiBufferPoint::new(row.0, 0);
21499                if let Some((buffer, buffer_point, _)) =
21500                    self.buffer.read(cx).point_to_buffer_point(point, cx)
21501                {
21502                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
21503                    new_selections_by_buffer
21504                        .entry(buffer)
21505                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
21506                        .0
21507                        .push(buffer_offset..buffer_offset)
21508                }
21509            }
21510            None => {
21511                let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
21512                let multi_buffer = self.buffer.read(cx);
21513                for selection in selections {
21514                    for (snapshot, range, _, anchor) in multi_buffer
21515                        .snapshot(cx)
21516                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
21517                    {
21518                        if let Some(anchor) = anchor {
21519                            let Some(buffer_handle) = multi_buffer.buffer_for_anchor(anchor, cx)
21520                            else {
21521                                continue;
21522                            };
21523                            let offset = text::ToOffset::to_offset(
21524                                &anchor.text_anchor,
21525                                &buffer_handle.read(cx).snapshot(),
21526                            );
21527                            let range = offset..offset;
21528                            new_selections_by_buffer
21529                                .entry(buffer_handle)
21530                                .or_insert((Vec::new(), None))
21531                                .0
21532                                .push(range)
21533                        } else {
21534                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
21535                            else {
21536                                continue;
21537                            };
21538                            new_selections_by_buffer
21539                                .entry(buffer_handle)
21540                                .or_insert((Vec::new(), None))
21541                                .0
21542                                .push(range)
21543                        }
21544                    }
21545                }
21546            }
21547        }
21548
21549        new_selections_by_buffer
21550            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
21551
21552        if new_selections_by_buffer.is_empty() {
21553            return;
21554        }
21555
21556        // We defer the pane interaction because we ourselves are a workspace item
21557        // and activating a new item causes the pane to call a method on us reentrantly,
21558        // which panics if we're on the stack.
21559        window.defer(cx, move |window, cx| {
21560            workspace.update(cx, |workspace, cx| {
21561                let pane = if split {
21562                    workspace.adjacent_pane(window, cx)
21563                } else {
21564                    workspace.active_pane().clone()
21565                };
21566
21567                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
21568                    let editor = buffer
21569                        .read(cx)
21570                        .file()
21571                        .is_none()
21572                        .then(|| {
21573                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
21574                            // so `workspace.open_project_item` will never find them, always opening a new editor.
21575                            // Instead, we try to activate the existing editor in the pane first.
21576                            let (editor, pane_item_index) =
21577                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
21578                                    let editor = item.downcast::<Editor>()?;
21579                                    let singleton_buffer =
21580                                        editor.read(cx).buffer().read(cx).as_singleton()?;
21581                                    if singleton_buffer == buffer {
21582                                        Some((editor, i))
21583                                    } else {
21584                                        None
21585                                    }
21586                                })?;
21587                            pane.update(cx, |pane, cx| {
21588                                pane.activate_item(pane_item_index, true, true, window, cx)
21589                            });
21590                            Some(editor)
21591                        })
21592                        .flatten()
21593                        .unwrap_or_else(|| {
21594                            workspace.open_project_item::<Self>(
21595                                pane.clone(),
21596                                buffer,
21597                                true,
21598                                true,
21599                                window,
21600                                cx,
21601                            )
21602                        });
21603
21604                    editor.update(cx, |editor, cx| {
21605                        let autoscroll = match scroll_offset {
21606                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
21607                            None => Autoscroll::newest(),
21608                        };
21609                        let nav_history = editor.nav_history.take();
21610                        editor.change_selections(
21611                            SelectionEffects::scroll(autoscroll),
21612                            window,
21613                            cx,
21614                            |s| {
21615                                s.select_ranges(ranges);
21616                            },
21617                        );
21618                        editor.nav_history = nav_history;
21619                    });
21620                }
21621            })
21622        });
21623    }
21624
21625    // For now, don't allow opening excerpts in buffers that aren't backed by
21626    // regular project files.
21627    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
21628        file.is_none_or(|file| project::File::from_dyn(Some(file)).is_some())
21629    }
21630
21631    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
21632        let snapshot = self.buffer.read(cx).read(cx);
21633        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
21634        Some(
21635            ranges
21636                .iter()
21637                .map(move |range| {
21638                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
21639                })
21640                .collect(),
21641        )
21642    }
21643
21644    fn selection_replacement_ranges(
21645        &self,
21646        range: Range<OffsetUtf16>,
21647        cx: &mut App,
21648    ) -> Vec<Range<OffsetUtf16>> {
21649        let selections = self
21650            .selections
21651            .all::<OffsetUtf16>(&self.display_snapshot(cx));
21652        let newest_selection = selections
21653            .iter()
21654            .max_by_key(|selection| selection.id)
21655            .unwrap();
21656        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
21657        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
21658        let snapshot = self.buffer.read(cx).read(cx);
21659        selections
21660            .into_iter()
21661            .map(|mut selection| {
21662                selection.start.0 =
21663                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
21664                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
21665                snapshot.clip_offset_utf16(selection.start, Bias::Left)
21666                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
21667            })
21668            .collect()
21669    }
21670
21671    fn report_editor_event(
21672        &self,
21673        reported_event: ReportEditorEvent,
21674        file_extension: Option<String>,
21675        cx: &App,
21676    ) {
21677        if cfg!(any(test, feature = "test-support")) {
21678            return;
21679        }
21680
21681        let Some(project) = &self.project else { return };
21682
21683        // If None, we are in a file without an extension
21684        let file = self
21685            .buffer
21686            .read(cx)
21687            .as_singleton()
21688            .and_then(|b| b.read(cx).file());
21689        let file_extension = file_extension.or(file
21690            .as_ref()
21691            .and_then(|file| Path::new(file.file_name(cx)).extension())
21692            .and_then(|e| e.to_str())
21693            .map(|a| a.to_string()));
21694
21695        let vim_mode = vim_flavor(cx).is_some();
21696
21697        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
21698        let copilot_enabled = edit_predictions_provider
21699            == language::language_settings::EditPredictionProvider::Copilot;
21700        let copilot_enabled_for_language = self
21701            .buffer
21702            .read(cx)
21703            .language_settings(cx)
21704            .show_edit_predictions;
21705
21706        let project = project.read(cx);
21707        let event_type = reported_event.event_type();
21708
21709        if let ReportEditorEvent::Saved { auto_saved } = reported_event {
21710            telemetry::event!(
21711                event_type,
21712                type = if auto_saved {"autosave"} else {"manual"},
21713                file_extension,
21714                vim_mode,
21715                copilot_enabled,
21716                copilot_enabled_for_language,
21717                edit_predictions_provider,
21718                is_via_ssh = project.is_via_remote_server(),
21719            );
21720        } else {
21721            telemetry::event!(
21722                event_type,
21723                file_extension,
21724                vim_mode,
21725                copilot_enabled,
21726                copilot_enabled_for_language,
21727                edit_predictions_provider,
21728                is_via_ssh = project.is_via_remote_server(),
21729            );
21730        };
21731    }
21732
21733    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
21734    /// with each line being an array of {text, highlight} objects.
21735    fn copy_highlight_json(
21736        &mut self,
21737        _: &CopyHighlightJson,
21738        window: &mut Window,
21739        cx: &mut Context<Self>,
21740    ) {
21741        #[derive(Serialize)]
21742        struct Chunk<'a> {
21743            text: String,
21744            highlight: Option<&'a str>,
21745        }
21746
21747        let snapshot = self.buffer.read(cx).snapshot(cx);
21748        let range = self
21749            .selected_text_range(false, window, cx)
21750            .and_then(|selection| {
21751                if selection.range.is_empty() {
21752                    None
21753                } else {
21754                    Some(
21755                        snapshot.offset_utf16_to_offset(OffsetUtf16(selection.range.start))
21756                            ..snapshot.offset_utf16_to_offset(OffsetUtf16(selection.range.end)),
21757                    )
21758                }
21759            })
21760            .unwrap_or_else(|| 0..snapshot.len());
21761
21762        let chunks = snapshot.chunks(range, true);
21763        let mut lines = Vec::new();
21764        let mut line: VecDeque<Chunk> = VecDeque::new();
21765
21766        let Some(style) = self.style.as_ref() else {
21767            return;
21768        };
21769
21770        for chunk in chunks {
21771            let highlight = chunk
21772                .syntax_highlight_id
21773                .and_then(|id| id.name(&style.syntax));
21774            let mut chunk_lines = chunk.text.split('\n').peekable();
21775            while let Some(text) = chunk_lines.next() {
21776                let mut merged_with_last_token = false;
21777                if let Some(last_token) = line.back_mut()
21778                    && last_token.highlight == highlight
21779                {
21780                    last_token.text.push_str(text);
21781                    merged_with_last_token = true;
21782                }
21783
21784                if !merged_with_last_token {
21785                    line.push_back(Chunk {
21786                        text: text.into(),
21787                        highlight,
21788                    });
21789                }
21790
21791                if chunk_lines.peek().is_some() {
21792                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
21793                        line.pop_front();
21794                    }
21795                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
21796                        line.pop_back();
21797                    }
21798
21799                    lines.push(mem::take(&mut line));
21800                }
21801            }
21802        }
21803
21804        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
21805            return;
21806        };
21807        cx.write_to_clipboard(ClipboardItem::new_string(lines));
21808    }
21809
21810    pub fn open_context_menu(
21811        &mut self,
21812        _: &OpenContextMenu,
21813        window: &mut Window,
21814        cx: &mut Context<Self>,
21815    ) {
21816        self.request_autoscroll(Autoscroll::newest(), cx);
21817        let position = self
21818            .selections
21819            .newest_display(&self.display_snapshot(cx))
21820            .start;
21821        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
21822    }
21823
21824    pub fn replay_insert_event(
21825        &mut self,
21826        text: &str,
21827        relative_utf16_range: Option<Range<isize>>,
21828        window: &mut Window,
21829        cx: &mut Context<Self>,
21830    ) {
21831        if !self.input_enabled {
21832            cx.emit(EditorEvent::InputIgnored { text: text.into() });
21833            return;
21834        }
21835        if let Some(relative_utf16_range) = relative_utf16_range {
21836            let selections = self
21837                .selections
21838                .all::<OffsetUtf16>(&self.display_snapshot(cx));
21839            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21840                let new_ranges = selections.into_iter().map(|range| {
21841                    let start = OffsetUtf16(
21842                        range
21843                            .head()
21844                            .0
21845                            .saturating_add_signed(relative_utf16_range.start),
21846                    );
21847                    let end = OffsetUtf16(
21848                        range
21849                            .head()
21850                            .0
21851                            .saturating_add_signed(relative_utf16_range.end),
21852                    );
21853                    start..end
21854                });
21855                s.select_ranges(new_ranges);
21856            });
21857        }
21858
21859        self.handle_input(text, window, cx);
21860    }
21861
21862    pub fn is_focused(&self, window: &Window) -> bool {
21863        self.focus_handle.is_focused(window)
21864    }
21865
21866    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21867        cx.emit(EditorEvent::Focused);
21868
21869        if let Some(descendant) = self
21870            .last_focused_descendant
21871            .take()
21872            .and_then(|descendant| descendant.upgrade())
21873        {
21874            window.focus(&descendant);
21875        } else {
21876            if let Some(blame) = self.blame.as_ref() {
21877                blame.update(cx, GitBlame::focus)
21878            }
21879
21880            self.blink_manager.update(cx, BlinkManager::enable);
21881            self.show_cursor_names(window, cx);
21882            self.buffer.update(cx, |buffer, cx| {
21883                buffer.finalize_last_transaction(cx);
21884                if self.leader_id.is_none() {
21885                    buffer.set_active_selections(
21886                        &self.selections.disjoint_anchors_arc(),
21887                        self.selections.line_mode(),
21888                        self.cursor_shape,
21889                        cx,
21890                    );
21891                }
21892            });
21893        }
21894    }
21895
21896    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
21897        cx.emit(EditorEvent::FocusedIn)
21898    }
21899
21900    fn handle_focus_out(
21901        &mut self,
21902        event: FocusOutEvent,
21903        _window: &mut Window,
21904        cx: &mut Context<Self>,
21905    ) {
21906        if event.blurred != self.focus_handle {
21907            self.last_focused_descendant = Some(event.blurred);
21908        }
21909        self.selection_drag_state = SelectionDragState::None;
21910        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
21911    }
21912
21913    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21914        self.blink_manager.update(cx, BlinkManager::disable);
21915        self.buffer
21916            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
21917
21918        if let Some(blame) = self.blame.as_ref() {
21919            blame.update(cx, GitBlame::blur)
21920        }
21921        if !self.hover_state.focused(window, cx) {
21922            hide_hover(self, cx);
21923        }
21924        if !self
21925            .context_menu
21926            .borrow()
21927            .as_ref()
21928            .is_some_and(|context_menu| context_menu.focused(window, cx))
21929        {
21930            self.hide_context_menu(window, cx);
21931        }
21932        self.take_active_edit_prediction(cx);
21933        cx.emit(EditorEvent::Blurred);
21934        cx.notify();
21935    }
21936
21937    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21938        let mut pending: String = window
21939            .pending_input_keystrokes()
21940            .into_iter()
21941            .flatten()
21942            .filter_map(|keystroke| {
21943                if keystroke.modifiers.is_subset_of(&Modifiers::shift()) {
21944                    keystroke.key_char.clone()
21945                } else {
21946                    None
21947                }
21948            })
21949            .collect();
21950
21951        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
21952            pending = "".to_string();
21953        }
21954
21955        let existing_pending = self
21956            .text_highlights::<PendingInput>(cx)
21957            .map(|(_, ranges)| ranges.to_vec());
21958        if existing_pending.is_none() && pending.is_empty() {
21959            return;
21960        }
21961        let transaction =
21962            self.transact(window, cx, |this, window, cx| {
21963                let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
21964                let edits = selections
21965                    .iter()
21966                    .map(|selection| (selection.end..selection.end, pending.clone()));
21967                this.edit(edits, cx);
21968                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21969                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
21970                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
21971                    }));
21972                });
21973                if let Some(existing_ranges) = existing_pending {
21974                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
21975                    this.edit(edits, cx);
21976                }
21977            });
21978
21979        let snapshot = self.snapshot(window, cx);
21980        let ranges = self
21981            .selections
21982            .all::<usize>(&snapshot.display_snapshot)
21983            .into_iter()
21984            .map(|selection| {
21985                snapshot.buffer_snapshot().anchor_after(selection.end)
21986                    ..snapshot
21987                        .buffer_snapshot()
21988                        .anchor_before(selection.end + pending.len())
21989            })
21990            .collect();
21991
21992        if pending.is_empty() {
21993            self.clear_highlights::<PendingInput>(cx);
21994        } else {
21995            self.highlight_text::<PendingInput>(
21996                ranges,
21997                HighlightStyle {
21998                    underline: Some(UnderlineStyle {
21999                        thickness: px(1.),
22000                        color: None,
22001                        wavy: false,
22002                    }),
22003                    ..Default::default()
22004                },
22005                cx,
22006            );
22007        }
22008
22009        self.ime_transaction = self.ime_transaction.or(transaction);
22010        if let Some(transaction) = self.ime_transaction {
22011            self.buffer.update(cx, |buffer, cx| {
22012                buffer.group_until_transaction(transaction, cx);
22013            });
22014        }
22015
22016        if self.text_highlights::<PendingInput>(cx).is_none() {
22017            self.ime_transaction.take();
22018        }
22019    }
22020
22021    pub fn register_action_renderer(
22022        &mut self,
22023        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
22024    ) -> Subscription {
22025        let id = self.next_editor_action_id.post_inc();
22026        self.editor_actions
22027            .borrow_mut()
22028            .insert(id, Box::new(listener));
22029
22030        let editor_actions = self.editor_actions.clone();
22031        Subscription::new(move || {
22032            editor_actions.borrow_mut().remove(&id);
22033        })
22034    }
22035
22036    pub fn register_action<A: Action>(
22037        &mut self,
22038        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
22039    ) -> Subscription {
22040        let id = self.next_editor_action_id.post_inc();
22041        let listener = Arc::new(listener);
22042        self.editor_actions.borrow_mut().insert(
22043            id,
22044            Box::new(move |_, window, _| {
22045                let listener = listener.clone();
22046                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
22047                    let action = action.downcast_ref().unwrap();
22048                    if phase == DispatchPhase::Bubble {
22049                        listener(action, window, cx)
22050                    }
22051                })
22052            }),
22053        );
22054
22055        let editor_actions = self.editor_actions.clone();
22056        Subscription::new(move || {
22057            editor_actions.borrow_mut().remove(&id);
22058        })
22059    }
22060
22061    pub fn file_header_size(&self) -> u32 {
22062        FILE_HEADER_HEIGHT
22063    }
22064
22065    pub fn restore(
22066        &mut self,
22067        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
22068        window: &mut Window,
22069        cx: &mut Context<Self>,
22070    ) {
22071        let workspace = self.workspace();
22072        let project = self.project();
22073        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
22074            let mut tasks = Vec::new();
22075            for (buffer_id, changes) in revert_changes {
22076                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
22077                    buffer.update(cx, |buffer, cx| {
22078                        buffer.edit(
22079                            changes
22080                                .into_iter()
22081                                .map(|(range, text)| (range, text.to_string())),
22082                            None,
22083                            cx,
22084                        );
22085                    });
22086
22087                    if let Some(project) =
22088                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
22089                    {
22090                        project.update(cx, |project, cx| {
22091                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
22092                        })
22093                    }
22094                }
22095            }
22096            tasks
22097        });
22098        cx.spawn_in(window, async move |_, cx| {
22099            for (buffer, task) in save_tasks {
22100                let result = task.await;
22101                if result.is_err() {
22102                    let Some(path) = buffer
22103                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
22104                        .ok()
22105                    else {
22106                        continue;
22107                    };
22108                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
22109                        let Some(task) = cx
22110                            .update_window_entity(workspace, |workspace, window, cx| {
22111                                workspace
22112                                    .open_path_preview(path, None, false, false, false, window, cx)
22113                            })
22114                            .ok()
22115                        else {
22116                            continue;
22117                        };
22118                        task.await.log_err();
22119                    }
22120                }
22121            }
22122        })
22123        .detach();
22124        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
22125            selections.refresh()
22126        });
22127    }
22128
22129    pub fn to_pixel_point(
22130        &self,
22131        source: multi_buffer::Anchor,
22132        editor_snapshot: &EditorSnapshot,
22133        window: &mut Window,
22134    ) -> Option<gpui::Point<Pixels>> {
22135        let source_point = source.to_display_point(editor_snapshot);
22136        self.display_to_pixel_point(source_point, editor_snapshot, window)
22137    }
22138
22139    pub fn display_to_pixel_point(
22140        &self,
22141        source: DisplayPoint,
22142        editor_snapshot: &EditorSnapshot,
22143        window: &mut Window,
22144    ) -> Option<gpui::Point<Pixels>> {
22145        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
22146        let text_layout_details = self.text_layout_details(window);
22147        let scroll_top = text_layout_details
22148            .scroll_anchor
22149            .scroll_position(editor_snapshot)
22150            .y;
22151
22152        if source.row().as_f64() < scroll_top.floor() {
22153            return None;
22154        }
22155        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
22156        let source_y = line_height * (source.row().as_f64() - scroll_top) as f32;
22157        Some(gpui::Point::new(source_x, source_y))
22158    }
22159
22160    pub fn has_visible_completions_menu(&self) -> bool {
22161        !self.edit_prediction_preview_is_active()
22162            && self.context_menu.borrow().as_ref().is_some_and(|menu| {
22163                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
22164            })
22165    }
22166
22167    pub fn register_addon<T: Addon>(&mut self, instance: T) {
22168        if self.mode.is_minimap() {
22169            return;
22170        }
22171        self.addons
22172            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
22173    }
22174
22175    pub fn unregister_addon<T: Addon>(&mut self) {
22176        self.addons.remove(&std::any::TypeId::of::<T>());
22177    }
22178
22179    pub fn addon<T: Addon>(&self) -> Option<&T> {
22180        let type_id = std::any::TypeId::of::<T>();
22181        self.addons
22182            .get(&type_id)
22183            .and_then(|item| item.to_any().downcast_ref::<T>())
22184    }
22185
22186    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
22187        let type_id = std::any::TypeId::of::<T>();
22188        self.addons
22189            .get_mut(&type_id)
22190            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
22191    }
22192
22193    fn character_dimensions(&self, window: &mut Window) -> CharacterDimensions {
22194        let text_layout_details = self.text_layout_details(window);
22195        let style = &text_layout_details.editor_style;
22196        let font_id = window.text_system().resolve_font(&style.text.font());
22197        let font_size = style.text.font_size.to_pixels(window.rem_size());
22198        let line_height = style.text.line_height_in_pixels(window.rem_size());
22199        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
22200        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
22201
22202        CharacterDimensions {
22203            em_width,
22204            em_advance,
22205            line_height,
22206        }
22207    }
22208
22209    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
22210        self.load_diff_task.clone()
22211    }
22212
22213    fn read_metadata_from_db(
22214        &mut self,
22215        item_id: u64,
22216        workspace_id: WorkspaceId,
22217        window: &mut Window,
22218        cx: &mut Context<Editor>,
22219    ) {
22220        if self.buffer_kind(cx) == ItemBufferKind::Singleton
22221            && !self.mode.is_minimap()
22222            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
22223        {
22224            let buffer_snapshot = OnceCell::new();
22225
22226            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err()
22227                && !folds.is_empty()
22228            {
22229                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
22230                self.fold_ranges(
22231                    folds
22232                        .into_iter()
22233                        .map(|(start, end)| {
22234                            snapshot.clip_offset(start, Bias::Left)
22235                                ..snapshot.clip_offset(end, Bias::Right)
22236                        })
22237                        .collect(),
22238                    false,
22239                    window,
22240                    cx,
22241                );
22242            }
22243
22244            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err()
22245                && !selections.is_empty()
22246            {
22247                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
22248                // skip adding the initial selection to selection history
22249                self.selection_history.mode = SelectionHistoryMode::Skipping;
22250                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
22251                    s.select_ranges(selections.into_iter().map(|(start, end)| {
22252                        snapshot.clip_offset(start, Bias::Left)
22253                            ..snapshot.clip_offset(end, Bias::Right)
22254                    }));
22255                });
22256                self.selection_history.mode = SelectionHistoryMode::Normal;
22257            };
22258        }
22259
22260        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
22261    }
22262
22263    fn update_lsp_data(
22264        &mut self,
22265        for_buffer: Option<BufferId>,
22266        window: &mut Window,
22267        cx: &mut Context<'_, Self>,
22268    ) {
22269        self.pull_diagnostics(for_buffer, window, cx);
22270        self.refresh_colors_for_visible_range(for_buffer, window, cx);
22271    }
22272
22273    fn register_visible_buffers(&mut self, cx: &mut Context<Self>) {
22274        if self.ignore_lsp_data() {
22275            return;
22276        }
22277        for (_, (visible_buffer, _, _)) in self.visible_excerpts(cx) {
22278            self.register_buffer(visible_buffer.read(cx).remote_id(), cx);
22279        }
22280    }
22281
22282    fn register_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
22283        if self.ignore_lsp_data() {
22284            return;
22285        }
22286
22287        if !self.registered_buffers.contains_key(&buffer_id)
22288            && let Some(project) = self.project.as_ref()
22289        {
22290            if let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) {
22291                project.update(cx, |project, cx| {
22292                    self.registered_buffers.insert(
22293                        buffer_id,
22294                        project.register_buffer_with_language_servers(&buffer, cx),
22295                    );
22296                });
22297            } else {
22298                self.registered_buffers.remove(&buffer_id);
22299            }
22300        }
22301    }
22302
22303    fn ignore_lsp_data(&self) -> bool {
22304        // `ActiveDiagnostic::All` is a special mode where editor's diagnostics are managed by the external view,
22305        // skip any LSP updates for it.
22306        self.active_diagnostics == ActiveDiagnostic::All || !self.mode().is_full()
22307    }
22308}
22309
22310fn edit_for_markdown_paste<'a>(
22311    buffer: &MultiBufferSnapshot,
22312    range: Range<usize>,
22313    to_insert: &'a str,
22314    url: Option<url::Url>,
22315) -> (Range<usize>, Cow<'a, str>) {
22316    if url.is_none() {
22317        return (range, Cow::Borrowed(to_insert));
22318    };
22319
22320    let old_text = buffer.text_for_range(range.clone()).collect::<String>();
22321
22322    let new_text = if range.is_empty() || url::Url::parse(&old_text).is_ok() {
22323        Cow::Borrowed(to_insert)
22324    } else {
22325        Cow::Owned(format!("[{old_text}]({to_insert})"))
22326    };
22327    (range, new_text)
22328}
22329
22330#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
22331pub enum VimFlavor {
22332    Vim,
22333    Helix,
22334}
22335
22336pub fn vim_flavor(cx: &App) -> Option<VimFlavor> {
22337    if vim_mode_setting::HelixModeSetting::try_get(cx)
22338        .map(|helix_mode| helix_mode.0)
22339        .unwrap_or(false)
22340    {
22341        Some(VimFlavor::Helix)
22342    } else if vim_mode_setting::VimModeSetting::try_get(cx)
22343        .map(|vim_mode| vim_mode.0)
22344        .unwrap_or(false)
22345    {
22346        Some(VimFlavor::Vim)
22347    } else {
22348        None // neither vim nor helix mode
22349    }
22350}
22351
22352fn process_completion_for_edit(
22353    completion: &Completion,
22354    intent: CompletionIntent,
22355    buffer: &Entity<Buffer>,
22356    cursor_position: &text::Anchor,
22357    cx: &mut Context<Editor>,
22358) -> CompletionEdit {
22359    let buffer = buffer.read(cx);
22360    let buffer_snapshot = buffer.snapshot();
22361    let (snippet, new_text) = if completion.is_snippet() {
22362        let mut snippet_source = completion.new_text.clone();
22363        // Workaround for typescript language server issues so that methods don't expand within
22364        // strings and functions with type expressions. The previous point is used because the query
22365        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
22366        let previous_point = text::ToPoint::to_point(cursor_position, &buffer_snapshot);
22367        let previous_point = if previous_point.column > 0 {
22368            cursor_position.to_previous_offset(&buffer_snapshot)
22369        } else {
22370            cursor_position.to_offset(&buffer_snapshot)
22371        };
22372        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point)
22373            && scope.prefers_label_for_snippet_in_completion()
22374            && let Some(label) = completion.label()
22375            && matches!(
22376                completion.kind(),
22377                Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
22378            )
22379        {
22380            snippet_source = label;
22381        }
22382        match Snippet::parse(&snippet_source).log_err() {
22383            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
22384            None => (None, completion.new_text.clone()),
22385        }
22386    } else {
22387        (None, completion.new_text.clone())
22388    };
22389
22390    let mut range_to_replace = {
22391        let replace_range = &completion.replace_range;
22392        if let CompletionSource::Lsp {
22393            insert_range: Some(insert_range),
22394            ..
22395        } = &completion.source
22396        {
22397            debug_assert_eq!(
22398                insert_range.start, replace_range.start,
22399                "insert_range and replace_range should start at the same position"
22400            );
22401            debug_assert!(
22402                insert_range
22403                    .start
22404                    .cmp(cursor_position, &buffer_snapshot)
22405                    .is_le(),
22406                "insert_range should start before or at cursor position"
22407            );
22408            debug_assert!(
22409                replace_range
22410                    .start
22411                    .cmp(cursor_position, &buffer_snapshot)
22412                    .is_le(),
22413                "replace_range should start before or at cursor position"
22414            );
22415
22416            let should_replace = match intent {
22417                CompletionIntent::CompleteWithInsert => false,
22418                CompletionIntent::CompleteWithReplace => true,
22419                CompletionIntent::Complete | CompletionIntent::Compose => {
22420                    let insert_mode =
22421                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
22422                            .completions
22423                            .lsp_insert_mode;
22424                    match insert_mode {
22425                        LspInsertMode::Insert => false,
22426                        LspInsertMode::Replace => true,
22427                        LspInsertMode::ReplaceSubsequence => {
22428                            let mut text_to_replace = buffer.chars_for_range(
22429                                buffer.anchor_before(replace_range.start)
22430                                    ..buffer.anchor_after(replace_range.end),
22431                            );
22432                            let mut current_needle = text_to_replace.next();
22433                            for haystack_ch in completion.label.text.chars() {
22434                                if let Some(needle_ch) = current_needle
22435                                    && haystack_ch.eq_ignore_ascii_case(&needle_ch)
22436                                {
22437                                    current_needle = text_to_replace.next();
22438                                }
22439                            }
22440                            current_needle.is_none()
22441                        }
22442                        LspInsertMode::ReplaceSuffix => {
22443                            if replace_range
22444                                .end
22445                                .cmp(cursor_position, &buffer_snapshot)
22446                                .is_gt()
22447                            {
22448                                let range_after_cursor = *cursor_position..replace_range.end;
22449                                let text_after_cursor = buffer
22450                                    .text_for_range(
22451                                        buffer.anchor_before(range_after_cursor.start)
22452                                            ..buffer.anchor_after(range_after_cursor.end),
22453                                    )
22454                                    .collect::<String>()
22455                                    .to_ascii_lowercase();
22456                                completion
22457                                    .label
22458                                    .text
22459                                    .to_ascii_lowercase()
22460                                    .ends_with(&text_after_cursor)
22461                            } else {
22462                                true
22463                            }
22464                        }
22465                    }
22466                }
22467            };
22468
22469            if should_replace {
22470                replace_range.clone()
22471            } else {
22472                insert_range.clone()
22473            }
22474        } else {
22475            replace_range.clone()
22476        }
22477    };
22478
22479    if range_to_replace
22480        .end
22481        .cmp(cursor_position, &buffer_snapshot)
22482        .is_lt()
22483    {
22484        range_to_replace.end = *cursor_position;
22485    }
22486
22487    CompletionEdit {
22488        new_text,
22489        replace_range: range_to_replace.to_offset(buffer),
22490        snippet,
22491    }
22492}
22493
22494struct CompletionEdit {
22495    new_text: String,
22496    replace_range: Range<usize>,
22497    snippet: Option<Snippet>,
22498}
22499
22500fn insert_extra_newline_brackets(
22501    buffer: &MultiBufferSnapshot,
22502    range: Range<usize>,
22503    language: &language::LanguageScope,
22504) -> bool {
22505    let leading_whitespace_len = buffer
22506        .reversed_chars_at(range.start)
22507        .take_while(|c| c.is_whitespace() && *c != '\n')
22508        .map(|c| c.len_utf8())
22509        .sum::<usize>();
22510    let trailing_whitespace_len = buffer
22511        .chars_at(range.end)
22512        .take_while(|c| c.is_whitespace() && *c != '\n')
22513        .map(|c| c.len_utf8())
22514        .sum::<usize>();
22515    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
22516
22517    language.brackets().any(|(pair, enabled)| {
22518        let pair_start = pair.start.trim_end();
22519        let pair_end = pair.end.trim_start();
22520
22521        enabled
22522            && pair.newline
22523            && buffer.contains_str_at(range.end, pair_end)
22524            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
22525    })
22526}
22527
22528fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
22529    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
22530        [(buffer, range, _)] => (*buffer, range.clone()),
22531        _ => return false,
22532    };
22533    let pair = {
22534        let mut result: Option<BracketMatch> = None;
22535
22536        for pair in buffer
22537            .all_bracket_ranges(range.clone())
22538            .filter(move |pair| {
22539                pair.open_range.start <= range.start && pair.close_range.end >= range.end
22540            })
22541        {
22542            let len = pair.close_range.end - pair.open_range.start;
22543
22544            if let Some(existing) = &result {
22545                let existing_len = existing.close_range.end - existing.open_range.start;
22546                if len > existing_len {
22547                    continue;
22548                }
22549            }
22550
22551            result = Some(pair);
22552        }
22553
22554        result
22555    };
22556    let Some(pair) = pair else {
22557        return false;
22558    };
22559    pair.newline_only
22560        && buffer
22561            .chars_for_range(pair.open_range.end..range.start)
22562            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
22563            .all(|c| c.is_whitespace() && c != '\n')
22564}
22565
22566fn update_uncommitted_diff_for_buffer(
22567    editor: Entity<Editor>,
22568    project: &Entity<Project>,
22569    buffers: impl IntoIterator<Item = Entity<Buffer>>,
22570    buffer: Entity<MultiBuffer>,
22571    cx: &mut App,
22572) -> Task<()> {
22573    let mut tasks = Vec::new();
22574    project.update(cx, |project, cx| {
22575        for buffer in buffers {
22576            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
22577                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
22578            }
22579        }
22580    });
22581    cx.spawn(async move |cx| {
22582        let diffs = future::join_all(tasks).await;
22583        if editor
22584            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
22585            .unwrap_or(false)
22586        {
22587            return;
22588        }
22589
22590        buffer
22591            .update(cx, |buffer, cx| {
22592                for diff in diffs.into_iter().flatten() {
22593                    buffer.add_diff(diff, cx);
22594                }
22595            })
22596            .ok();
22597    })
22598}
22599
22600fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
22601    let tab_size = tab_size.get() as usize;
22602    let mut width = offset;
22603
22604    for ch in text.chars() {
22605        width += if ch == '\t' {
22606            tab_size - (width % tab_size)
22607        } else {
22608            1
22609        };
22610    }
22611
22612    width - offset
22613}
22614
22615#[cfg(test)]
22616mod tests {
22617    use super::*;
22618
22619    #[test]
22620    fn test_string_size_with_expanded_tabs() {
22621        let nz = |val| NonZeroU32::new(val).unwrap();
22622        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
22623        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
22624        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
22625        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
22626        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
22627        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
22628        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
22629        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
22630    }
22631}
22632
22633/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
22634struct WordBreakingTokenizer<'a> {
22635    input: &'a str,
22636}
22637
22638impl<'a> WordBreakingTokenizer<'a> {
22639    fn new(input: &'a str) -> Self {
22640        Self { input }
22641    }
22642}
22643
22644fn is_char_ideographic(ch: char) -> bool {
22645    use unicode_script::Script::*;
22646    use unicode_script::UnicodeScript;
22647    matches!(ch.script(), Han | Tangut | Yi)
22648}
22649
22650fn is_grapheme_ideographic(text: &str) -> bool {
22651    text.chars().any(is_char_ideographic)
22652}
22653
22654fn is_grapheme_whitespace(text: &str) -> bool {
22655    text.chars().any(|x| x.is_whitespace())
22656}
22657
22658fn should_stay_with_preceding_ideograph(text: &str) -> bool {
22659    text.chars()
22660        .next()
22661        .is_some_and(|ch| matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…'))
22662}
22663
22664#[derive(PartialEq, Eq, Debug, Clone, Copy)]
22665enum WordBreakToken<'a> {
22666    Word { token: &'a str, grapheme_len: usize },
22667    InlineWhitespace { token: &'a str, grapheme_len: usize },
22668    Newline,
22669}
22670
22671impl<'a> Iterator for WordBreakingTokenizer<'a> {
22672    /// Yields a span, the count of graphemes in the token, and whether it was
22673    /// whitespace. Note that it also breaks at word boundaries.
22674    type Item = WordBreakToken<'a>;
22675
22676    fn next(&mut self) -> Option<Self::Item> {
22677        use unicode_segmentation::UnicodeSegmentation;
22678        if self.input.is_empty() {
22679            return None;
22680        }
22681
22682        let mut iter = self.input.graphemes(true).peekable();
22683        let mut offset = 0;
22684        let mut grapheme_len = 0;
22685        if let Some(first_grapheme) = iter.next() {
22686            let is_newline = first_grapheme == "\n";
22687            let is_whitespace = is_grapheme_whitespace(first_grapheme);
22688            offset += first_grapheme.len();
22689            grapheme_len += 1;
22690            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
22691                if let Some(grapheme) = iter.peek().copied()
22692                    && should_stay_with_preceding_ideograph(grapheme)
22693                {
22694                    offset += grapheme.len();
22695                    grapheme_len += 1;
22696                }
22697            } else {
22698                let mut words = self.input[offset..].split_word_bound_indices().peekable();
22699                let mut next_word_bound = words.peek().copied();
22700                if next_word_bound.is_some_and(|(i, _)| i == 0) {
22701                    next_word_bound = words.next();
22702                }
22703                while let Some(grapheme) = iter.peek().copied() {
22704                    if next_word_bound.is_some_and(|(i, _)| i == offset) {
22705                        break;
22706                    };
22707                    if is_grapheme_whitespace(grapheme) != is_whitespace
22708                        || (grapheme == "\n") != is_newline
22709                    {
22710                        break;
22711                    };
22712                    offset += grapheme.len();
22713                    grapheme_len += 1;
22714                    iter.next();
22715                }
22716            }
22717            let token = &self.input[..offset];
22718            self.input = &self.input[offset..];
22719            if token == "\n" {
22720                Some(WordBreakToken::Newline)
22721            } else if is_whitespace {
22722                Some(WordBreakToken::InlineWhitespace {
22723                    token,
22724                    grapheme_len,
22725                })
22726            } else {
22727                Some(WordBreakToken::Word {
22728                    token,
22729                    grapheme_len,
22730                })
22731            }
22732        } else {
22733            None
22734        }
22735    }
22736}
22737
22738#[test]
22739fn test_word_breaking_tokenizer() {
22740    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
22741        ("", &[]),
22742        ("  ", &[whitespace("  ", 2)]),
22743        ("Ʒ", &[word("Ʒ", 1)]),
22744        ("Ǽ", &[word("Ǽ", 1)]),
22745        ("", &[word("", 1)]),
22746        ("⋑⋑", &[word("⋑⋑", 2)]),
22747        (
22748            "原理,进而",
22749            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
22750        ),
22751        (
22752            "hello world",
22753            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
22754        ),
22755        (
22756            "hello, world",
22757            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
22758        ),
22759        (
22760            "  hello world",
22761            &[
22762                whitespace("  ", 2),
22763                word("hello", 5),
22764                whitespace(" ", 1),
22765                word("world", 5),
22766            ],
22767        ),
22768        (
22769            "这是什么 \n 钢笔",
22770            &[
22771                word("", 1),
22772                word("", 1),
22773                word("", 1),
22774                word("", 1),
22775                whitespace(" ", 1),
22776                newline(),
22777                whitespace(" ", 1),
22778                word("", 1),
22779                word("", 1),
22780            ],
22781        ),
22782        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
22783    ];
22784
22785    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
22786        WordBreakToken::Word {
22787            token,
22788            grapheme_len,
22789        }
22790    }
22791
22792    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
22793        WordBreakToken::InlineWhitespace {
22794            token,
22795            grapheme_len,
22796        }
22797    }
22798
22799    fn newline() -> WordBreakToken<'static> {
22800        WordBreakToken::Newline
22801    }
22802
22803    for (input, result) in tests {
22804        assert_eq!(
22805            WordBreakingTokenizer::new(input)
22806                .collect::<Vec<_>>()
22807                .as_slice(),
22808            *result,
22809        );
22810    }
22811}
22812
22813fn wrap_with_prefix(
22814    first_line_prefix: String,
22815    subsequent_lines_prefix: String,
22816    unwrapped_text: String,
22817    wrap_column: usize,
22818    tab_size: NonZeroU32,
22819    preserve_existing_whitespace: bool,
22820) -> String {
22821    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
22822    let subsequent_lines_prefix_len =
22823        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
22824    let mut wrapped_text = String::new();
22825    let mut current_line = first_line_prefix;
22826    let mut is_first_line = true;
22827
22828    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
22829    let mut current_line_len = first_line_prefix_len;
22830    let mut in_whitespace = false;
22831    for token in tokenizer {
22832        let have_preceding_whitespace = in_whitespace;
22833        match token {
22834            WordBreakToken::Word {
22835                token,
22836                grapheme_len,
22837            } => {
22838                in_whitespace = false;
22839                let current_prefix_len = if is_first_line {
22840                    first_line_prefix_len
22841                } else {
22842                    subsequent_lines_prefix_len
22843                };
22844                if current_line_len + grapheme_len > wrap_column
22845                    && current_line_len != current_prefix_len
22846                {
22847                    wrapped_text.push_str(current_line.trim_end());
22848                    wrapped_text.push('\n');
22849                    is_first_line = false;
22850                    current_line = subsequent_lines_prefix.clone();
22851                    current_line_len = subsequent_lines_prefix_len;
22852                }
22853                current_line.push_str(token);
22854                current_line_len += grapheme_len;
22855            }
22856            WordBreakToken::InlineWhitespace {
22857                mut token,
22858                mut grapheme_len,
22859            } => {
22860                in_whitespace = true;
22861                if have_preceding_whitespace && !preserve_existing_whitespace {
22862                    continue;
22863                }
22864                if !preserve_existing_whitespace {
22865                    // Keep a single whitespace grapheme as-is
22866                    if let Some(first) =
22867                        unicode_segmentation::UnicodeSegmentation::graphemes(token, true).next()
22868                    {
22869                        token = first;
22870                    } else {
22871                        token = " ";
22872                    }
22873                    grapheme_len = 1;
22874                }
22875                let current_prefix_len = if is_first_line {
22876                    first_line_prefix_len
22877                } else {
22878                    subsequent_lines_prefix_len
22879                };
22880                if current_line_len + grapheme_len > wrap_column {
22881                    wrapped_text.push_str(current_line.trim_end());
22882                    wrapped_text.push('\n');
22883                    is_first_line = false;
22884                    current_line = subsequent_lines_prefix.clone();
22885                    current_line_len = subsequent_lines_prefix_len;
22886                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
22887                    current_line.push_str(token);
22888                    current_line_len += grapheme_len;
22889                }
22890            }
22891            WordBreakToken::Newline => {
22892                in_whitespace = true;
22893                let current_prefix_len = if is_first_line {
22894                    first_line_prefix_len
22895                } else {
22896                    subsequent_lines_prefix_len
22897                };
22898                if preserve_existing_whitespace {
22899                    wrapped_text.push_str(current_line.trim_end());
22900                    wrapped_text.push('\n');
22901                    is_first_line = false;
22902                    current_line = subsequent_lines_prefix.clone();
22903                    current_line_len = subsequent_lines_prefix_len;
22904                } else if have_preceding_whitespace {
22905                    continue;
22906                } else if current_line_len + 1 > wrap_column
22907                    && current_line_len != current_prefix_len
22908                {
22909                    wrapped_text.push_str(current_line.trim_end());
22910                    wrapped_text.push('\n');
22911                    is_first_line = false;
22912                    current_line = subsequent_lines_prefix.clone();
22913                    current_line_len = subsequent_lines_prefix_len;
22914                } else if current_line_len != current_prefix_len {
22915                    current_line.push(' ');
22916                    current_line_len += 1;
22917                }
22918            }
22919        }
22920    }
22921
22922    if !current_line.is_empty() {
22923        wrapped_text.push_str(&current_line);
22924    }
22925    wrapped_text
22926}
22927
22928#[test]
22929fn test_wrap_with_prefix() {
22930    assert_eq!(
22931        wrap_with_prefix(
22932            "# ".to_string(),
22933            "# ".to_string(),
22934            "abcdefg".to_string(),
22935            4,
22936            NonZeroU32::new(4).unwrap(),
22937            false,
22938        ),
22939        "# abcdefg"
22940    );
22941    assert_eq!(
22942        wrap_with_prefix(
22943            "".to_string(),
22944            "".to_string(),
22945            "\thello world".to_string(),
22946            8,
22947            NonZeroU32::new(4).unwrap(),
22948            false,
22949        ),
22950        "hello\nworld"
22951    );
22952    assert_eq!(
22953        wrap_with_prefix(
22954            "// ".to_string(),
22955            "// ".to_string(),
22956            "xx \nyy zz aa bb cc".to_string(),
22957            12,
22958            NonZeroU32::new(4).unwrap(),
22959            false,
22960        ),
22961        "// xx yy zz\n// aa bb cc"
22962    );
22963    assert_eq!(
22964        wrap_with_prefix(
22965            String::new(),
22966            String::new(),
22967            "这是什么 \n 钢笔".to_string(),
22968            3,
22969            NonZeroU32::new(4).unwrap(),
22970            false,
22971        ),
22972        "这是什\n么 钢\n"
22973    );
22974    assert_eq!(
22975        wrap_with_prefix(
22976            String::new(),
22977            String::new(),
22978            format!("foo{}bar", '\u{2009}'), // thin space
22979            80,
22980            NonZeroU32::new(4).unwrap(),
22981            false,
22982        ),
22983        format!("foo{}bar", '\u{2009}')
22984    );
22985}
22986
22987pub trait CollaborationHub {
22988    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
22989    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
22990    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
22991}
22992
22993impl CollaborationHub for Entity<Project> {
22994    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
22995        self.read(cx).collaborators()
22996    }
22997
22998    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
22999        self.read(cx).user_store().read(cx).participant_indices()
23000    }
23001
23002    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
23003        let this = self.read(cx);
23004        let user_ids = this.collaborators().values().map(|c| c.user_id);
23005        this.user_store().read(cx).participant_names(user_ids, cx)
23006    }
23007}
23008
23009pub trait SemanticsProvider {
23010    fn hover(
23011        &self,
23012        buffer: &Entity<Buffer>,
23013        position: text::Anchor,
23014        cx: &mut App,
23015    ) -> Option<Task<Option<Vec<project::Hover>>>>;
23016
23017    fn inline_values(
23018        &self,
23019        buffer_handle: Entity<Buffer>,
23020        range: Range<text::Anchor>,
23021        cx: &mut App,
23022    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
23023
23024    fn applicable_inlay_chunks(
23025        &self,
23026        buffer: &Entity<Buffer>,
23027        ranges: &[Range<text::Anchor>],
23028        cx: &mut App,
23029    ) -> Vec<Range<BufferRow>>;
23030
23031    fn invalidate_inlay_hints(&self, for_buffers: &HashSet<BufferId>, cx: &mut App);
23032
23033    fn inlay_hints(
23034        &self,
23035        invalidate: InvalidationStrategy,
23036        buffer: Entity<Buffer>,
23037        ranges: Vec<Range<text::Anchor>>,
23038        known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
23039        cx: &mut App,
23040    ) -> Option<HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>>>;
23041
23042    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
23043
23044    fn document_highlights(
23045        &self,
23046        buffer: &Entity<Buffer>,
23047        position: text::Anchor,
23048        cx: &mut App,
23049    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
23050
23051    fn definitions(
23052        &self,
23053        buffer: &Entity<Buffer>,
23054        position: text::Anchor,
23055        kind: GotoDefinitionKind,
23056        cx: &mut App,
23057    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>>;
23058
23059    fn range_for_rename(
23060        &self,
23061        buffer: &Entity<Buffer>,
23062        position: text::Anchor,
23063        cx: &mut App,
23064    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
23065
23066    fn perform_rename(
23067        &self,
23068        buffer: &Entity<Buffer>,
23069        position: text::Anchor,
23070        new_name: String,
23071        cx: &mut App,
23072    ) -> Option<Task<Result<ProjectTransaction>>>;
23073}
23074
23075pub trait CompletionProvider {
23076    fn completions(
23077        &self,
23078        excerpt_id: ExcerptId,
23079        buffer: &Entity<Buffer>,
23080        buffer_position: text::Anchor,
23081        trigger: CompletionContext,
23082        window: &mut Window,
23083        cx: &mut Context<Editor>,
23084    ) -> Task<Result<Vec<CompletionResponse>>>;
23085
23086    fn resolve_completions(
23087        &self,
23088        _buffer: Entity<Buffer>,
23089        _completion_indices: Vec<usize>,
23090        _completions: Rc<RefCell<Box<[Completion]>>>,
23091        _cx: &mut Context<Editor>,
23092    ) -> Task<Result<bool>> {
23093        Task::ready(Ok(false))
23094    }
23095
23096    fn apply_additional_edits_for_completion(
23097        &self,
23098        _buffer: Entity<Buffer>,
23099        _completions: Rc<RefCell<Box<[Completion]>>>,
23100        _completion_index: usize,
23101        _push_to_history: bool,
23102        _cx: &mut Context<Editor>,
23103    ) -> Task<Result<Option<language::Transaction>>> {
23104        Task::ready(Ok(None))
23105    }
23106
23107    fn is_completion_trigger(
23108        &self,
23109        buffer: &Entity<Buffer>,
23110        position: language::Anchor,
23111        text: &str,
23112        trigger_in_words: bool,
23113        menu_is_open: bool,
23114        cx: &mut Context<Editor>,
23115    ) -> bool;
23116
23117    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
23118
23119    fn sort_completions(&self) -> bool {
23120        true
23121    }
23122
23123    fn filter_completions(&self) -> bool {
23124        true
23125    }
23126
23127    fn show_snippets(&self) -> bool {
23128        false
23129    }
23130}
23131
23132pub trait CodeActionProvider {
23133    fn id(&self) -> Arc<str>;
23134
23135    fn code_actions(
23136        &self,
23137        buffer: &Entity<Buffer>,
23138        range: Range<text::Anchor>,
23139        window: &mut Window,
23140        cx: &mut App,
23141    ) -> Task<Result<Vec<CodeAction>>>;
23142
23143    fn apply_code_action(
23144        &self,
23145        buffer_handle: Entity<Buffer>,
23146        action: CodeAction,
23147        excerpt_id: ExcerptId,
23148        push_to_history: bool,
23149        window: &mut Window,
23150        cx: &mut App,
23151    ) -> Task<Result<ProjectTransaction>>;
23152}
23153
23154impl CodeActionProvider for Entity<Project> {
23155    fn id(&self) -> Arc<str> {
23156        "project".into()
23157    }
23158
23159    fn code_actions(
23160        &self,
23161        buffer: &Entity<Buffer>,
23162        range: Range<text::Anchor>,
23163        _window: &mut Window,
23164        cx: &mut App,
23165    ) -> Task<Result<Vec<CodeAction>>> {
23166        self.update(cx, |project, cx| {
23167            let code_lens_actions = project.code_lens_actions(buffer, range.clone(), cx);
23168            let code_actions = project.code_actions(buffer, range, None, cx);
23169            cx.background_spawn(async move {
23170                let (code_lens_actions, code_actions) = join(code_lens_actions, code_actions).await;
23171                Ok(code_lens_actions
23172                    .context("code lens fetch")?
23173                    .into_iter()
23174                    .flatten()
23175                    .chain(
23176                        code_actions
23177                            .context("code action fetch")?
23178                            .into_iter()
23179                            .flatten(),
23180                    )
23181                    .collect())
23182            })
23183        })
23184    }
23185
23186    fn apply_code_action(
23187        &self,
23188        buffer_handle: Entity<Buffer>,
23189        action: CodeAction,
23190        _excerpt_id: ExcerptId,
23191        push_to_history: bool,
23192        _window: &mut Window,
23193        cx: &mut App,
23194    ) -> Task<Result<ProjectTransaction>> {
23195        self.update(cx, |project, cx| {
23196            project.apply_code_action(buffer_handle, action, push_to_history, cx)
23197        })
23198    }
23199}
23200
23201fn snippet_completions(
23202    project: &Project,
23203    buffer: &Entity<Buffer>,
23204    buffer_position: text::Anchor,
23205    cx: &mut App,
23206) -> Task<Result<CompletionResponse>> {
23207    let languages = buffer.read(cx).languages_at(buffer_position);
23208    let snippet_store = project.snippets().read(cx);
23209
23210    let scopes: Vec<_> = languages
23211        .iter()
23212        .filter_map(|language| {
23213            let language_name = language.lsp_id();
23214            let snippets = snippet_store.snippets_for(Some(language_name), cx);
23215
23216            if snippets.is_empty() {
23217                None
23218            } else {
23219                Some((language.default_scope(), snippets))
23220            }
23221        })
23222        .collect();
23223
23224    if scopes.is_empty() {
23225        return Task::ready(Ok(CompletionResponse {
23226            completions: vec![],
23227            display_options: CompletionDisplayOptions::default(),
23228            is_incomplete: false,
23229        }));
23230    }
23231
23232    let snapshot = buffer.read(cx).text_snapshot();
23233    let executor = cx.background_executor().clone();
23234
23235    cx.background_spawn(async move {
23236        let mut is_incomplete = false;
23237        let mut completions: Vec<Completion> = Vec::new();
23238        for (scope, snippets) in scopes.into_iter() {
23239            let classifier =
23240                CharClassifier::new(Some(scope)).scope_context(Some(CharScopeContext::Completion));
23241
23242            const MAX_WORD_PREFIX_LEN: usize = 128;
23243            let last_word: String = snapshot
23244                .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
23245                .take(MAX_WORD_PREFIX_LEN)
23246                .take_while(|c| classifier.is_word(*c))
23247                .collect::<String>()
23248                .chars()
23249                .rev()
23250                .collect();
23251
23252            if last_word.is_empty() {
23253                return Ok(CompletionResponse {
23254                    completions: vec![],
23255                    display_options: CompletionDisplayOptions::default(),
23256                    is_incomplete: true,
23257                });
23258            }
23259
23260            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
23261            let to_lsp = |point: &text::Anchor| {
23262                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
23263                point_to_lsp(end)
23264            };
23265            let lsp_end = to_lsp(&buffer_position);
23266
23267            let candidates = snippets
23268                .iter()
23269                .enumerate()
23270                .flat_map(|(ix, snippet)| {
23271                    snippet
23272                        .prefix
23273                        .iter()
23274                        .map(move |prefix| StringMatchCandidate::new(ix, prefix))
23275                })
23276                .collect::<Vec<StringMatchCandidate>>();
23277
23278            const MAX_RESULTS: usize = 100;
23279            let mut matches = fuzzy::match_strings(
23280                &candidates,
23281                &last_word,
23282                last_word.chars().any(|c| c.is_uppercase()),
23283                true,
23284                MAX_RESULTS,
23285                &Default::default(),
23286                executor.clone(),
23287            )
23288            .await;
23289
23290            if matches.len() >= MAX_RESULTS {
23291                is_incomplete = true;
23292            }
23293
23294            // Remove all candidates where the query's start does not match the start of any word in the candidate
23295            if let Some(query_start) = last_word.chars().next() {
23296                matches.retain(|string_match| {
23297                    split_words(&string_match.string).any(|word| {
23298                        // Check that the first codepoint of the word as lowercase matches the first
23299                        // codepoint of the query as lowercase
23300                        word.chars()
23301                            .flat_map(|codepoint| codepoint.to_lowercase())
23302                            .zip(query_start.to_lowercase())
23303                            .all(|(word_cp, query_cp)| word_cp == query_cp)
23304                    })
23305                });
23306            }
23307
23308            let matched_strings = matches
23309                .into_iter()
23310                .map(|m| m.string)
23311                .collect::<HashSet<_>>();
23312
23313            completions.extend(snippets.iter().filter_map(|snippet| {
23314                let matching_prefix = snippet
23315                    .prefix
23316                    .iter()
23317                    .find(|prefix| matched_strings.contains(*prefix))?;
23318                let start = as_offset - last_word.len();
23319                let start = snapshot.anchor_before(start);
23320                let range = start..buffer_position;
23321                let lsp_start = to_lsp(&start);
23322                let lsp_range = lsp::Range {
23323                    start: lsp_start,
23324                    end: lsp_end,
23325                };
23326                Some(Completion {
23327                    replace_range: range,
23328                    new_text: snippet.body.clone(),
23329                    source: CompletionSource::Lsp {
23330                        insert_range: None,
23331                        server_id: LanguageServerId(usize::MAX),
23332                        resolved: true,
23333                        lsp_completion: Box::new(lsp::CompletionItem {
23334                            label: snippet.prefix.first().unwrap().clone(),
23335                            kind: Some(CompletionItemKind::SNIPPET),
23336                            label_details: snippet.description.as_ref().map(|description| {
23337                                lsp::CompletionItemLabelDetails {
23338                                    detail: Some(description.clone()),
23339                                    description: None,
23340                                }
23341                            }),
23342                            insert_text_format: Some(InsertTextFormat::SNIPPET),
23343                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
23344                                lsp::InsertReplaceEdit {
23345                                    new_text: snippet.body.clone(),
23346                                    insert: lsp_range,
23347                                    replace: lsp_range,
23348                                },
23349                            )),
23350                            filter_text: Some(snippet.body.clone()),
23351                            sort_text: Some(char::MAX.to_string()),
23352                            ..lsp::CompletionItem::default()
23353                        }),
23354                        lsp_defaults: None,
23355                    },
23356                    label: CodeLabel::plain(matching_prefix.clone(), None),
23357                    icon_path: None,
23358                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
23359                        single_line: snippet.name.clone().into(),
23360                        plain_text: snippet
23361                            .description
23362                            .clone()
23363                            .map(|description| description.into()),
23364                    }),
23365                    insert_text_mode: None,
23366                    confirm: None,
23367                })
23368            }))
23369        }
23370
23371        Ok(CompletionResponse {
23372            completions,
23373            display_options: CompletionDisplayOptions::default(),
23374            is_incomplete,
23375        })
23376    })
23377}
23378
23379impl CompletionProvider for Entity<Project> {
23380    fn completions(
23381        &self,
23382        _excerpt_id: ExcerptId,
23383        buffer: &Entity<Buffer>,
23384        buffer_position: text::Anchor,
23385        options: CompletionContext,
23386        _window: &mut Window,
23387        cx: &mut Context<Editor>,
23388    ) -> Task<Result<Vec<CompletionResponse>>> {
23389        self.update(cx, |project, cx| {
23390            let task = project.completions(buffer, buffer_position, options, cx);
23391            cx.background_spawn(task)
23392        })
23393    }
23394
23395    fn resolve_completions(
23396        &self,
23397        buffer: Entity<Buffer>,
23398        completion_indices: Vec<usize>,
23399        completions: Rc<RefCell<Box<[Completion]>>>,
23400        cx: &mut Context<Editor>,
23401    ) -> Task<Result<bool>> {
23402        self.update(cx, |project, cx| {
23403            project.lsp_store().update(cx, |lsp_store, cx| {
23404                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
23405            })
23406        })
23407    }
23408
23409    fn apply_additional_edits_for_completion(
23410        &self,
23411        buffer: Entity<Buffer>,
23412        completions: Rc<RefCell<Box<[Completion]>>>,
23413        completion_index: usize,
23414        push_to_history: bool,
23415        cx: &mut Context<Editor>,
23416    ) -> Task<Result<Option<language::Transaction>>> {
23417        self.update(cx, |project, cx| {
23418            project.lsp_store().update(cx, |lsp_store, cx| {
23419                lsp_store.apply_additional_edits_for_completion(
23420                    buffer,
23421                    completions,
23422                    completion_index,
23423                    push_to_history,
23424                    cx,
23425                )
23426            })
23427        })
23428    }
23429
23430    fn is_completion_trigger(
23431        &self,
23432        buffer: &Entity<Buffer>,
23433        position: language::Anchor,
23434        text: &str,
23435        trigger_in_words: bool,
23436        menu_is_open: bool,
23437        cx: &mut Context<Editor>,
23438    ) -> bool {
23439        let mut chars = text.chars();
23440        let char = if let Some(char) = chars.next() {
23441            char
23442        } else {
23443            return false;
23444        };
23445        if chars.next().is_some() {
23446            return false;
23447        }
23448
23449        let buffer = buffer.read(cx);
23450        let snapshot = buffer.snapshot();
23451        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
23452            return false;
23453        }
23454        let classifier = snapshot
23455            .char_classifier_at(position)
23456            .scope_context(Some(CharScopeContext::Completion));
23457        if trigger_in_words && classifier.is_word(char) {
23458            return true;
23459        }
23460
23461        buffer.completion_triggers().contains(text)
23462    }
23463
23464    fn show_snippets(&self) -> bool {
23465        true
23466    }
23467}
23468
23469impl SemanticsProvider for Entity<Project> {
23470    fn hover(
23471        &self,
23472        buffer: &Entity<Buffer>,
23473        position: text::Anchor,
23474        cx: &mut App,
23475    ) -> Option<Task<Option<Vec<project::Hover>>>> {
23476        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
23477    }
23478
23479    fn document_highlights(
23480        &self,
23481        buffer: &Entity<Buffer>,
23482        position: text::Anchor,
23483        cx: &mut App,
23484    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
23485        Some(self.update(cx, |project, cx| {
23486            project.document_highlights(buffer, position, cx)
23487        }))
23488    }
23489
23490    fn definitions(
23491        &self,
23492        buffer: &Entity<Buffer>,
23493        position: text::Anchor,
23494        kind: GotoDefinitionKind,
23495        cx: &mut App,
23496    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>> {
23497        Some(self.update(cx, |project, cx| match kind {
23498            GotoDefinitionKind::Symbol => project.definitions(buffer, position, cx),
23499            GotoDefinitionKind::Declaration => project.declarations(buffer, position, cx),
23500            GotoDefinitionKind::Type => project.type_definitions(buffer, position, cx),
23501            GotoDefinitionKind::Implementation => project.implementations(buffer, position, cx),
23502        }))
23503    }
23504
23505    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
23506        self.update(cx, |project, cx| {
23507            if project
23508                .active_debug_session(cx)
23509                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
23510            {
23511                return true;
23512            }
23513
23514            buffer.update(cx, |buffer, cx| {
23515                project.any_language_server_supports_inlay_hints(buffer, cx)
23516            })
23517        })
23518    }
23519
23520    fn inline_values(
23521        &self,
23522        buffer_handle: Entity<Buffer>,
23523        range: Range<text::Anchor>,
23524        cx: &mut App,
23525    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
23526        self.update(cx, |project, cx| {
23527            let (session, active_stack_frame) = project.active_debug_session(cx)?;
23528
23529            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
23530        })
23531    }
23532
23533    fn applicable_inlay_chunks(
23534        &self,
23535        buffer: &Entity<Buffer>,
23536        ranges: &[Range<text::Anchor>],
23537        cx: &mut App,
23538    ) -> Vec<Range<BufferRow>> {
23539        self.read(cx).lsp_store().update(cx, |lsp_store, cx| {
23540            lsp_store.applicable_inlay_chunks(buffer, ranges, cx)
23541        })
23542    }
23543
23544    fn invalidate_inlay_hints(&self, for_buffers: &HashSet<BufferId>, cx: &mut App) {
23545        self.read(cx).lsp_store().update(cx, |lsp_store, _| {
23546            lsp_store.invalidate_inlay_hints(for_buffers)
23547        });
23548    }
23549
23550    fn inlay_hints(
23551        &self,
23552        invalidate: InvalidationStrategy,
23553        buffer: Entity<Buffer>,
23554        ranges: Vec<Range<text::Anchor>>,
23555        known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
23556        cx: &mut App,
23557    ) -> Option<HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>>> {
23558        Some(self.read(cx).lsp_store().update(cx, |lsp_store, cx| {
23559            lsp_store.inlay_hints(invalidate, buffer, ranges, known_chunks, cx)
23560        }))
23561    }
23562
23563    fn range_for_rename(
23564        &self,
23565        buffer: &Entity<Buffer>,
23566        position: text::Anchor,
23567        cx: &mut App,
23568    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
23569        Some(self.update(cx, |project, cx| {
23570            let buffer = buffer.clone();
23571            let task = project.prepare_rename(buffer.clone(), position, cx);
23572            cx.spawn(async move |_, cx| {
23573                Ok(match task.await? {
23574                    PrepareRenameResponse::Success(range) => Some(range),
23575                    PrepareRenameResponse::InvalidPosition => None,
23576                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
23577                        // Fallback on using TreeSitter info to determine identifier range
23578                        buffer.read_with(cx, |buffer, _| {
23579                            let snapshot = buffer.snapshot();
23580                            let (range, kind) = snapshot.surrounding_word(position, None);
23581                            if kind != Some(CharKind::Word) {
23582                                return None;
23583                            }
23584                            Some(
23585                                snapshot.anchor_before(range.start)
23586                                    ..snapshot.anchor_after(range.end),
23587                            )
23588                        })?
23589                    }
23590                })
23591            })
23592        }))
23593    }
23594
23595    fn perform_rename(
23596        &self,
23597        buffer: &Entity<Buffer>,
23598        position: text::Anchor,
23599        new_name: String,
23600        cx: &mut App,
23601    ) -> Option<Task<Result<ProjectTransaction>>> {
23602        Some(self.update(cx, |project, cx| {
23603            project.perform_rename(buffer.clone(), position, new_name, cx)
23604        }))
23605    }
23606}
23607
23608fn consume_contiguous_rows(
23609    contiguous_row_selections: &mut Vec<Selection<Point>>,
23610    selection: &Selection<Point>,
23611    display_map: &DisplaySnapshot,
23612    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
23613) -> (MultiBufferRow, MultiBufferRow) {
23614    contiguous_row_selections.push(selection.clone());
23615    let start_row = starting_row(selection, display_map);
23616    let mut end_row = ending_row(selection, display_map);
23617
23618    while let Some(next_selection) = selections.peek() {
23619        if next_selection.start.row <= end_row.0 {
23620            end_row = ending_row(next_selection, display_map);
23621            contiguous_row_selections.push(selections.next().unwrap().clone());
23622        } else {
23623            break;
23624        }
23625    }
23626    (start_row, end_row)
23627}
23628
23629fn starting_row(selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
23630    if selection.start.column > 0 {
23631        MultiBufferRow(display_map.prev_line_boundary(selection.start).0.row)
23632    } else {
23633        MultiBufferRow(selection.start.row)
23634    }
23635}
23636
23637fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
23638    if next_selection.end.column > 0 || next_selection.is_empty() {
23639        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
23640    } else {
23641        MultiBufferRow(next_selection.end.row)
23642    }
23643}
23644
23645impl EditorSnapshot {
23646    pub fn remote_selections_in_range<'a>(
23647        &'a self,
23648        range: &'a Range<Anchor>,
23649        collaboration_hub: &dyn CollaborationHub,
23650        cx: &'a App,
23651    ) -> impl 'a + Iterator<Item = RemoteSelection> {
23652        let participant_names = collaboration_hub.user_names(cx);
23653        let participant_indices = collaboration_hub.user_participant_indices(cx);
23654        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
23655        let collaborators_by_replica_id = collaborators_by_peer_id
23656            .values()
23657            .map(|collaborator| (collaborator.replica_id, collaborator))
23658            .collect::<HashMap<_, _>>();
23659        self.buffer_snapshot()
23660            .selections_in_range(range, false)
23661            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
23662                if replica_id == ReplicaId::AGENT {
23663                    Some(RemoteSelection {
23664                        replica_id,
23665                        selection,
23666                        cursor_shape,
23667                        line_mode,
23668                        collaborator_id: CollaboratorId::Agent,
23669                        user_name: Some("Agent".into()),
23670                        color: cx.theme().players().agent(),
23671                    })
23672                } else {
23673                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
23674                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
23675                    let user_name = participant_names.get(&collaborator.user_id).cloned();
23676                    Some(RemoteSelection {
23677                        replica_id,
23678                        selection,
23679                        cursor_shape,
23680                        line_mode,
23681                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
23682                        user_name,
23683                        color: if let Some(index) = participant_index {
23684                            cx.theme().players().color_for_participant(index.0)
23685                        } else {
23686                            cx.theme().players().absent()
23687                        },
23688                    })
23689                }
23690            })
23691    }
23692
23693    pub fn hunks_for_ranges(
23694        &self,
23695        ranges: impl IntoIterator<Item = Range<Point>>,
23696    ) -> Vec<MultiBufferDiffHunk> {
23697        let mut hunks = Vec::new();
23698        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
23699            HashMap::default();
23700        for query_range in ranges {
23701            let query_rows =
23702                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
23703            for hunk in self.buffer_snapshot().diff_hunks_in_range(
23704                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
23705            ) {
23706                // Include deleted hunks that are adjacent to the query range, because
23707                // otherwise they would be missed.
23708                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
23709                if hunk.status().is_deleted() {
23710                    intersects_range |= hunk.row_range.start == query_rows.end;
23711                    intersects_range |= hunk.row_range.end == query_rows.start;
23712                }
23713                if intersects_range {
23714                    if !processed_buffer_rows
23715                        .entry(hunk.buffer_id)
23716                        .or_default()
23717                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
23718                    {
23719                        continue;
23720                    }
23721                    hunks.push(hunk);
23722                }
23723            }
23724        }
23725
23726        hunks
23727    }
23728
23729    fn display_diff_hunks_for_rows<'a>(
23730        &'a self,
23731        display_rows: Range<DisplayRow>,
23732        folded_buffers: &'a HashSet<BufferId>,
23733    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
23734        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
23735        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
23736
23737        self.buffer_snapshot()
23738            .diff_hunks_in_range(buffer_start..buffer_end)
23739            .filter_map(|hunk| {
23740                if folded_buffers.contains(&hunk.buffer_id) {
23741                    return None;
23742                }
23743
23744                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
23745                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
23746
23747                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
23748                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
23749
23750                let display_hunk = if hunk_display_start.column() != 0 {
23751                    DisplayDiffHunk::Folded {
23752                        display_row: hunk_display_start.row(),
23753                    }
23754                } else {
23755                    let mut end_row = hunk_display_end.row();
23756                    if hunk_display_end.column() > 0 {
23757                        end_row.0 += 1;
23758                    }
23759                    let is_created_file = hunk.is_created_file();
23760                    DisplayDiffHunk::Unfolded {
23761                        status: hunk.status(),
23762                        diff_base_byte_range: hunk.diff_base_byte_range,
23763                        display_row_range: hunk_display_start.row()..end_row,
23764                        multi_buffer_range: Anchor::range_in_buffer(
23765                            hunk.excerpt_id,
23766                            hunk.buffer_id,
23767                            hunk.buffer_range,
23768                        ),
23769                        is_created_file,
23770                    }
23771                };
23772
23773                Some(display_hunk)
23774            })
23775    }
23776
23777    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
23778        self.display_snapshot
23779            .buffer_snapshot()
23780            .language_at(position)
23781    }
23782
23783    pub fn is_focused(&self) -> bool {
23784        self.is_focused
23785    }
23786
23787    pub fn placeholder_text(&self) -> Option<String> {
23788        self.placeholder_display_snapshot
23789            .as_ref()
23790            .map(|display_map| display_map.text())
23791    }
23792
23793    pub fn scroll_position(&self) -> gpui::Point<ScrollOffset> {
23794        self.scroll_anchor.scroll_position(&self.display_snapshot)
23795    }
23796
23797    fn gutter_dimensions(
23798        &self,
23799        font_id: FontId,
23800        font_size: Pixels,
23801        max_line_number_width: Pixels,
23802        cx: &App,
23803    ) -> Option<GutterDimensions> {
23804        if !self.show_gutter {
23805            return None;
23806        }
23807
23808        let ch_width = cx.text_system().ch_width(font_id, font_size).log_err()?;
23809        let ch_advance = cx.text_system().ch_advance(font_id, font_size).log_err()?;
23810
23811        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
23812            matches!(
23813                ProjectSettings::get_global(cx).git.git_gutter,
23814                GitGutterSetting::TrackedFiles
23815            )
23816        });
23817        let gutter_settings = EditorSettings::get_global(cx).gutter;
23818        let show_line_numbers = self
23819            .show_line_numbers
23820            .unwrap_or(gutter_settings.line_numbers);
23821        let line_gutter_width = if show_line_numbers {
23822            // Avoid flicker-like gutter resizes when the line number gains another digit by
23823            // only resizing the gutter on files with > 10**min_line_number_digits lines.
23824            let min_width_for_number_on_gutter =
23825                ch_advance * gutter_settings.min_line_number_digits as f32;
23826            max_line_number_width.max(min_width_for_number_on_gutter)
23827        } else {
23828            0.0.into()
23829        };
23830
23831        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
23832        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
23833
23834        let git_blame_entries_width =
23835            self.git_blame_gutter_max_author_length
23836                .map(|max_author_length| {
23837                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
23838                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
23839
23840                    /// The number of characters to dedicate to gaps and margins.
23841                    const SPACING_WIDTH: usize = 4;
23842
23843                    let max_char_count = max_author_length.min(renderer.max_author_length())
23844                        + ::git::SHORT_SHA_LENGTH
23845                        + MAX_RELATIVE_TIMESTAMP.len()
23846                        + SPACING_WIDTH;
23847
23848                    ch_advance * max_char_count
23849                });
23850
23851        let is_singleton = self.buffer_snapshot().is_singleton();
23852
23853        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
23854        left_padding += if !is_singleton {
23855            ch_width * 4.0
23856        } else if show_runnables || show_breakpoints {
23857            ch_width * 3.0
23858        } else if show_git_gutter && show_line_numbers {
23859            ch_width * 2.0
23860        } else if show_git_gutter || show_line_numbers {
23861            ch_width
23862        } else {
23863            px(0.)
23864        };
23865
23866        let shows_folds = is_singleton && gutter_settings.folds;
23867
23868        let right_padding = if shows_folds && show_line_numbers {
23869            ch_width * 4.0
23870        } else if shows_folds || (!is_singleton && show_line_numbers) {
23871            ch_width * 3.0
23872        } else if show_line_numbers {
23873            ch_width
23874        } else {
23875            px(0.)
23876        };
23877
23878        Some(GutterDimensions {
23879            left_padding,
23880            right_padding,
23881            width: line_gutter_width + left_padding + right_padding,
23882            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
23883            git_blame_entries_width,
23884        })
23885    }
23886
23887    pub fn render_crease_toggle(
23888        &self,
23889        buffer_row: MultiBufferRow,
23890        row_contains_cursor: bool,
23891        editor: Entity<Editor>,
23892        window: &mut Window,
23893        cx: &mut App,
23894    ) -> Option<AnyElement> {
23895        let folded = self.is_line_folded(buffer_row);
23896        let mut is_foldable = false;
23897
23898        if let Some(crease) = self
23899            .crease_snapshot
23900            .query_row(buffer_row, self.buffer_snapshot())
23901        {
23902            is_foldable = true;
23903            match crease {
23904                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
23905                    if let Some(render_toggle) = render_toggle {
23906                        let toggle_callback =
23907                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
23908                                if folded {
23909                                    editor.update(cx, |editor, cx| {
23910                                        editor.fold_at(buffer_row, window, cx)
23911                                    });
23912                                } else {
23913                                    editor.update(cx, |editor, cx| {
23914                                        editor.unfold_at(buffer_row, window, cx)
23915                                    });
23916                                }
23917                            });
23918                        return Some((render_toggle)(
23919                            buffer_row,
23920                            folded,
23921                            toggle_callback,
23922                            window,
23923                            cx,
23924                        ));
23925                    }
23926                }
23927            }
23928        }
23929
23930        is_foldable |= self.starts_indent(buffer_row);
23931
23932        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
23933            Some(
23934                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
23935                    .toggle_state(folded)
23936                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
23937                        if folded {
23938                            this.unfold_at(buffer_row, window, cx);
23939                        } else {
23940                            this.fold_at(buffer_row, window, cx);
23941                        }
23942                    }))
23943                    .into_any_element(),
23944            )
23945        } else {
23946            None
23947        }
23948    }
23949
23950    pub fn render_crease_trailer(
23951        &self,
23952        buffer_row: MultiBufferRow,
23953        window: &mut Window,
23954        cx: &mut App,
23955    ) -> Option<AnyElement> {
23956        let folded = self.is_line_folded(buffer_row);
23957        if let Crease::Inline { render_trailer, .. } = self
23958            .crease_snapshot
23959            .query_row(buffer_row, self.buffer_snapshot())?
23960        {
23961            let render_trailer = render_trailer.as_ref()?;
23962            Some(render_trailer(buffer_row, folded, window, cx))
23963        } else {
23964            None
23965        }
23966    }
23967}
23968
23969impl Deref for EditorSnapshot {
23970    type Target = DisplaySnapshot;
23971
23972    fn deref(&self) -> &Self::Target {
23973        &self.display_snapshot
23974    }
23975}
23976
23977#[derive(Clone, Debug, PartialEq, Eq)]
23978pub enum EditorEvent {
23979    InputIgnored {
23980        text: Arc<str>,
23981    },
23982    InputHandled {
23983        utf16_range_to_replace: Option<Range<isize>>,
23984        text: Arc<str>,
23985    },
23986    ExcerptsAdded {
23987        buffer: Entity<Buffer>,
23988        predecessor: ExcerptId,
23989        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
23990    },
23991    ExcerptsRemoved {
23992        ids: Vec<ExcerptId>,
23993        removed_buffer_ids: Vec<BufferId>,
23994    },
23995    BufferFoldToggled {
23996        ids: Vec<ExcerptId>,
23997        folded: bool,
23998    },
23999    ExcerptsEdited {
24000        ids: Vec<ExcerptId>,
24001    },
24002    ExcerptsExpanded {
24003        ids: Vec<ExcerptId>,
24004    },
24005    BufferEdited,
24006    Edited {
24007        transaction_id: clock::Lamport,
24008    },
24009    Reparsed(BufferId),
24010    Focused,
24011    FocusedIn,
24012    Blurred,
24013    DirtyChanged,
24014    Saved,
24015    TitleChanged,
24016    SelectionsChanged {
24017        local: bool,
24018    },
24019    ScrollPositionChanged {
24020        local: bool,
24021        autoscroll: bool,
24022    },
24023    TransactionUndone {
24024        transaction_id: clock::Lamport,
24025    },
24026    TransactionBegun {
24027        transaction_id: clock::Lamport,
24028    },
24029    CursorShapeChanged,
24030    BreadcrumbsChanged,
24031    PushedToNavHistory {
24032        anchor: Anchor,
24033        is_deactivate: bool,
24034    },
24035}
24036
24037impl EventEmitter<EditorEvent> for Editor {}
24038
24039impl Focusable for Editor {
24040    fn focus_handle(&self, _cx: &App) -> FocusHandle {
24041        self.focus_handle.clone()
24042    }
24043}
24044
24045impl Render for Editor {
24046    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
24047        let settings = ThemeSettings::get_global(cx);
24048
24049        let mut text_style = match self.mode {
24050            EditorMode::SingleLine | EditorMode::AutoHeight { .. } => TextStyle {
24051                color: cx.theme().colors().editor_foreground,
24052                font_family: settings.ui_font.family.clone(),
24053                font_features: settings.ui_font.features.clone(),
24054                font_fallbacks: settings.ui_font.fallbacks.clone(),
24055                font_size: rems(0.875).into(),
24056                font_weight: settings.ui_font.weight,
24057                line_height: relative(settings.buffer_line_height.value()),
24058                ..Default::default()
24059            },
24060            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
24061                color: cx.theme().colors().editor_foreground,
24062                font_family: settings.buffer_font.family.clone(),
24063                font_features: settings.buffer_font.features.clone(),
24064                font_fallbacks: settings.buffer_font.fallbacks.clone(),
24065                font_size: settings.buffer_font_size(cx).into(),
24066                font_weight: settings.buffer_font.weight,
24067                line_height: relative(settings.buffer_line_height.value()),
24068                ..Default::default()
24069            },
24070        };
24071        if let Some(text_style_refinement) = &self.text_style_refinement {
24072            text_style.refine(text_style_refinement)
24073        }
24074
24075        let background = match self.mode {
24076            EditorMode::SingleLine => cx.theme().system().transparent,
24077            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
24078            EditorMode::Full { .. } => cx.theme().colors().editor_background,
24079            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
24080        };
24081
24082        EditorElement::new(
24083            &cx.entity(),
24084            EditorStyle {
24085                background,
24086                border: cx.theme().colors().border,
24087                local_player: cx.theme().players().local(),
24088                text: text_style,
24089                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
24090                syntax: cx.theme().syntax().clone(),
24091                status: cx.theme().status().clone(),
24092                inlay_hints_style: make_inlay_hints_style(cx),
24093                edit_prediction_styles: make_suggestion_styles(cx),
24094                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
24095                show_underlines: self.diagnostics_enabled(),
24096            },
24097        )
24098    }
24099}
24100
24101impl EntityInputHandler for Editor {
24102    fn text_for_range(
24103        &mut self,
24104        range_utf16: Range<usize>,
24105        adjusted_range: &mut Option<Range<usize>>,
24106        _: &mut Window,
24107        cx: &mut Context<Self>,
24108    ) -> Option<String> {
24109        let snapshot = self.buffer.read(cx).read(cx);
24110        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
24111        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
24112        if (start.0..end.0) != range_utf16 {
24113            adjusted_range.replace(start.0..end.0);
24114        }
24115        Some(snapshot.text_for_range(start..end).collect())
24116    }
24117
24118    fn selected_text_range(
24119        &mut self,
24120        ignore_disabled_input: bool,
24121        _: &mut Window,
24122        cx: &mut Context<Self>,
24123    ) -> Option<UTF16Selection> {
24124        // Prevent the IME menu from appearing when holding down an alphabetic key
24125        // while input is disabled.
24126        if !ignore_disabled_input && !self.input_enabled {
24127            return None;
24128        }
24129
24130        let selection = self
24131            .selections
24132            .newest::<OffsetUtf16>(&self.display_snapshot(cx));
24133        let range = selection.range();
24134
24135        Some(UTF16Selection {
24136            range: range.start.0..range.end.0,
24137            reversed: selection.reversed,
24138        })
24139    }
24140
24141    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
24142        let snapshot = self.buffer.read(cx).read(cx);
24143        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
24144        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
24145    }
24146
24147    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
24148        self.clear_highlights::<InputComposition>(cx);
24149        self.ime_transaction.take();
24150    }
24151
24152    fn replace_text_in_range(
24153        &mut self,
24154        range_utf16: Option<Range<usize>>,
24155        text: &str,
24156        window: &mut Window,
24157        cx: &mut Context<Self>,
24158    ) {
24159        if !self.input_enabled {
24160            cx.emit(EditorEvent::InputIgnored { text: text.into() });
24161            return;
24162        }
24163
24164        self.transact(window, cx, |this, window, cx| {
24165            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
24166                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
24167                Some(this.selection_replacement_ranges(range_utf16, cx))
24168            } else {
24169                this.marked_text_ranges(cx)
24170            };
24171
24172            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
24173                let newest_selection_id = this.selections.newest_anchor().id;
24174                this.selections
24175                    .all::<OffsetUtf16>(&this.display_snapshot(cx))
24176                    .iter()
24177                    .zip(ranges_to_replace.iter())
24178                    .find_map(|(selection, range)| {
24179                        if selection.id == newest_selection_id {
24180                            Some(
24181                                (range.start.0 as isize - selection.head().0 as isize)
24182                                    ..(range.end.0 as isize - selection.head().0 as isize),
24183                            )
24184                        } else {
24185                            None
24186                        }
24187                    })
24188            });
24189
24190            cx.emit(EditorEvent::InputHandled {
24191                utf16_range_to_replace: range_to_replace,
24192                text: text.into(),
24193            });
24194
24195            if let Some(new_selected_ranges) = new_selected_ranges {
24196                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
24197                    selections.select_ranges(new_selected_ranges)
24198                });
24199                this.backspace(&Default::default(), window, cx);
24200            }
24201
24202            this.handle_input(text, window, cx);
24203        });
24204
24205        if let Some(transaction) = self.ime_transaction {
24206            self.buffer.update(cx, |buffer, cx| {
24207                buffer.group_until_transaction(transaction, cx);
24208            });
24209        }
24210
24211        self.unmark_text(window, cx);
24212    }
24213
24214    fn replace_and_mark_text_in_range(
24215        &mut self,
24216        range_utf16: Option<Range<usize>>,
24217        text: &str,
24218        new_selected_range_utf16: Option<Range<usize>>,
24219        window: &mut Window,
24220        cx: &mut Context<Self>,
24221    ) {
24222        if !self.input_enabled {
24223            return;
24224        }
24225
24226        let transaction = self.transact(window, cx, |this, window, cx| {
24227            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
24228                let snapshot = this.buffer.read(cx).read(cx);
24229                if let Some(relative_range_utf16) = range_utf16.as_ref() {
24230                    for marked_range in &mut marked_ranges {
24231                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
24232                        marked_range.start.0 += relative_range_utf16.start;
24233                        marked_range.start =
24234                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
24235                        marked_range.end =
24236                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
24237                    }
24238                }
24239                Some(marked_ranges)
24240            } else if let Some(range_utf16) = range_utf16 {
24241                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
24242                Some(this.selection_replacement_ranges(range_utf16, cx))
24243            } else {
24244                None
24245            };
24246
24247            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
24248                let newest_selection_id = this.selections.newest_anchor().id;
24249                this.selections
24250                    .all::<OffsetUtf16>(&this.display_snapshot(cx))
24251                    .iter()
24252                    .zip(ranges_to_replace.iter())
24253                    .find_map(|(selection, range)| {
24254                        if selection.id == newest_selection_id {
24255                            Some(
24256                                (range.start.0 as isize - selection.head().0 as isize)
24257                                    ..(range.end.0 as isize - selection.head().0 as isize),
24258                            )
24259                        } else {
24260                            None
24261                        }
24262                    })
24263            });
24264
24265            cx.emit(EditorEvent::InputHandled {
24266                utf16_range_to_replace: range_to_replace,
24267                text: text.into(),
24268            });
24269
24270            if let Some(ranges) = ranges_to_replace {
24271                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
24272                    s.select_ranges(ranges)
24273                });
24274            }
24275
24276            let marked_ranges = {
24277                let snapshot = this.buffer.read(cx).read(cx);
24278                this.selections
24279                    .disjoint_anchors_arc()
24280                    .iter()
24281                    .map(|selection| {
24282                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
24283                    })
24284                    .collect::<Vec<_>>()
24285            };
24286
24287            if text.is_empty() {
24288                this.unmark_text(window, cx);
24289            } else {
24290                this.highlight_text::<InputComposition>(
24291                    marked_ranges.clone(),
24292                    HighlightStyle {
24293                        underline: Some(UnderlineStyle {
24294                            thickness: px(1.),
24295                            color: None,
24296                            wavy: false,
24297                        }),
24298                        ..Default::default()
24299                    },
24300                    cx,
24301                );
24302            }
24303
24304            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
24305            let use_autoclose = this.use_autoclose;
24306            let use_auto_surround = this.use_auto_surround;
24307            this.set_use_autoclose(false);
24308            this.set_use_auto_surround(false);
24309            this.handle_input(text, window, cx);
24310            this.set_use_autoclose(use_autoclose);
24311            this.set_use_auto_surround(use_auto_surround);
24312
24313            if let Some(new_selected_range) = new_selected_range_utf16 {
24314                let snapshot = this.buffer.read(cx).read(cx);
24315                let new_selected_ranges = marked_ranges
24316                    .into_iter()
24317                    .map(|marked_range| {
24318                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
24319                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
24320                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
24321                        snapshot.clip_offset_utf16(new_start, Bias::Left)
24322                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
24323                    })
24324                    .collect::<Vec<_>>();
24325
24326                drop(snapshot);
24327                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
24328                    selections.select_ranges(new_selected_ranges)
24329                });
24330            }
24331        });
24332
24333        self.ime_transaction = self.ime_transaction.or(transaction);
24334        if let Some(transaction) = self.ime_transaction {
24335            self.buffer.update(cx, |buffer, cx| {
24336                buffer.group_until_transaction(transaction, cx);
24337            });
24338        }
24339
24340        if self.text_highlights::<InputComposition>(cx).is_none() {
24341            self.ime_transaction.take();
24342        }
24343    }
24344
24345    fn bounds_for_range(
24346        &mut self,
24347        range_utf16: Range<usize>,
24348        element_bounds: gpui::Bounds<Pixels>,
24349        window: &mut Window,
24350        cx: &mut Context<Self>,
24351    ) -> Option<gpui::Bounds<Pixels>> {
24352        let text_layout_details = self.text_layout_details(window);
24353        let CharacterDimensions {
24354            em_width,
24355            em_advance,
24356            line_height,
24357        } = self.character_dimensions(window);
24358
24359        let snapshot = self.snapshot(window, cx);
24360        let scroll_position = snapshot.scroll_position();
24361        let scroll_left = scroll_position.x * ScrollOffset::from(em_advance);
24362
24363        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
24364        let x = Pixels::from(
24365            ScrollOffset::from(
24366                snapshot.x_for_display_point(start, &text_layout_details)
24367                    + self.gutter_dimensions.full_width(),
24368            ) - scroll_left,
24369        );
24370        let y = line_height * (start.row().as_f64() - scroll_position.y) as f32;
24371
24372        Some(Bounds {
24373            origin: element_bounds.origin + point(x, y),
24374            size: size(em_width, line_height),
24375        })
24376    }
24377
24378    fn character_index_for_point(
24379        &mut self,
24380        point: gpui::Point<Pixels>,
24381        _window: &mut Window,
24382        _cx: &mut Context<Self>,
24383    ) -> Option<usize> {
24384        let position_map = self.last_position_map.as_ref()?;
24385        if !position_map.text_hitbox.contains(&point) {
24386            return None;
24387        }
24388        let display_point = position_map.point_for_position(point).previous_valid;
24389        let anchor = position_map
24390            .snapshot
24391            .display_point_to_anchor(display_point, Bias::Left);
24392        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot());
24393        Some(utf16_offset.0)
24394    }
24395
24396    fn accepts_text_input(&self, _window: &mut Window, _cx: &mut Context<Self>) -> bool {
24397        self.input_enabled
24398    }
24399}
24400
24401trait SelectionExt {
24402    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
24403    fn spanned_rows(
24404        &self,
24405        include_end_if_at_line_start: bool,
24406        map: &DisplaySnapshot,
24407    ) -> Range<MultiBufferRow>;
24408}
24409
24410impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
24411    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
24412        let start = self
24413            .start
24414            .to_point(map.buffer_snapshot())
24415            .to_display_point(map);
24416        let end = self
24417            .end
24418            .to_point(map.buffer_snapshot())
24419            .to_display_point(map);
24420        if self.reversed {
24421            end..start
24422        } else {
24423            start..end
24424        }
24425    }
24426
24427    fn spanned_rows(
24428        &self,
24429        include_end_if_at_line_start: bool,
24430        map: &DisplaySnapshot,
24431    ) -> Range<MultiBufferRow> {
24432        let start = self.start.to_point(map.buffer_snapshot());
24433        let mut end = self.end.to_point(map.buffer_snapshot());
24434        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
24435            end.row -= 1;
24436        }
24437
24438        let buffer_start = map.prev_line_boundary(start).0;
24439        let buffer_end = map.next_line_boundary(end).0;
24440        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
24441    }
24442}
24443
24444impl<T: InvalidationRegion> InvalidationStack<T> {
24445    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
24446    where
24447        S: Clone + ToOffset,
24448    {
24449        while let Some(region) = self.last() {
24450            let all_selections_inside_invalidation_ranges =
24451                if selections.len() == region.ranges().len() {
24452                    selections
24453                        .iter()
24454                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
24455                        .all(|(selection, invalidation_range)| {
24456                            let head = selection.head().to_offset(buffer);
24457                            invalidation_range.start <= head && invalidation_range.end >= head
24458                        })
24459                } else {
24460                    false
24461                };
24462
24463            if all_selections_inside_invalidation_ranges {
24464                break;
24465            } else {
24466                self.pop();
24467            }
24468        }
24469    }
24470}
24471
24472impl<T> Default for InvalidationStack<T> {
24473    fn default() -> Self {
24474        Self(Default::default())
24475    }
24476}
24477
24478impl<T> Deref for InvalidationStack<T> {
24479    type Target = Vec<T>;
24480
24481    fn deref(&self) -> &Self::Target {
24482        &self.0
24483    }
24484}
24485
24486impl<T> DerefMut for InvalidationStack<T> {
24487    fn deref_mut(&mut self) -> &mut Self::Target {
24488        &mut self.0
24489    }
24490}
24491
24492impl InvalidationRegion for SnippetState {
24493    fn ranges(&self) -> &[Range<Anchor>] {
24494        &self.ranges[self.active_index]
24495    }
24496}
24497
24498fn edit_prediction_edit_text(
24499    current_snapshot: &BufferSnapshot,
24500    edits: &[(Range<Anchor>, impl AsRef<str>)],
24501    edit_preview: &EditPreview,
24502    include_deletions: bool,
24503    cx: &App,
24504) -> HighlightedText {
24505    let edits = edits
24506        .iter()
24507        .map(|(anchor, text)| (anchor.start.text_anchor..anchor.end.text_anchor, text))
24508        .collect::<Vec<_>>();
24509
24510    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
24511}
24512
24513fn edit_prediction_fallback_text(edits: &[(Range<Anchor>, Arc<str>)], cx: &App) -> HighlightedText {
24514    // Fallback for providers that don't provide edit_preview (like Copilot/Supermaven)
24515    // Just show the raw edit text with basic styling
24516    let mut text = String::new();
24517    let mut highlights = Vec::new();
24518
24519    let insertion_highlight_style = HighlightStyle {
24520        color: Some(cx.theme().colors().text),
24521        ..Default::default()
24522    };
24523
24524    for (_, edit_text) in edits {
24525        let start_offset = text.len();
24526        text.push_str(edit_text);
24527        let end_offset = text.len();
24528
24529        if start_offset < end_offset {
24530            highlights.push((start_offset..end_offset, insertion_highlight_style));
24531        }
24532    }
24533
24534    HighlightedText {
24535        text: text.into(),
24536        highlights,
24537    }
24538}
24539
24540pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
24541    match severity {
24542        lsp::DiagnosticSeverity::ERROR => colors.error,
24543        lsp::DiagnosticSeverity::WARNING => colors.warning,
24544        lsp::DiagnosticSeverity::INFORMATION => colors.info,
24545        lsp::DiagnosticSeverity::HINT => colors.info,
24546        _ => colors.ignored,
24547    }
24548}
24549
24550pub fn styled_runs_for_code_label<'a>(
24551    label: &'a CodeLabel,
24552    syntax_theme: &'a theme::SyntaxTheme,
24553) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
24554    let fade_out = HighlightStyle {
24555        fade_out: Some(0.35),
24556        ..Default::default()
24557    };
24558
24559    let mut prev_end = label.filter_range.end;
24560    label
24561        .runs
24562        .iter()
24563        .enumerate()
24564        .flat_map(move |(ix, (range, highlight_id))| {
24565            let style = if let Some(style) = highlight_id.style(syntax_theme) {
24566                style
24567            } else {
24568                return Default::default();
24569            };
24570            let muted_style = style.highlight(fade_out);
24571
24572            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
24573            if range.start >= label.filter_range.end {
24574                if range.start > prev_end {
24575                    runs.push((prev_end..range.start, fade_out));
24576                }
24577                runs.push((range.clone(), muted_style));
24578            } else if range.end <= label.filter_range.end {
24579                runs.push((range.clone(), style));
24580            } else {
24581                runs.push((range.start..label.filter_range.end, style));
24582                runs.push((label.filter_range.end..range.end, muted_style));
24583            }
24584            prev_end = cmp::max(prev_end, range.end);
24585
24586            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
24587                runs.push((prev_end..label.text.len(), fade_out));
24588            }
24589
24590            runs
24591        })
24592}
24593
24594pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
24595    let mut prev_index = 0;
24596    let mut prev_codepoint: Option<char> = None;
24597    text.char_indices()
24598        .chain([(text.len(), '\0')])
24599        .filter_map(move |(index, codepoint)| {
24600            let prev_codepoint = prev_codepoint.replace(codepoint)?;
24601            let is_boundary = index == text.len()
24602                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
24603                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
24604            if is_boundary {
24605                let chunk = &text[prev_index..index];
24606                prev_index = index;
24607                Some(chunk)
24608            } else {
24609                None
24610            }
24611        })
24612}
24613
24614pub trait RangeToAnchorExt: Sized {
24615    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
24616
24617    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
24618        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot());
24619        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
24620    }
24621}
24622
24623impl<T: ToOffset> RangeToAnchorExt for Range<T> {
24624    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
24625        let start_offset = self.start.to_offset(snapshot);
24626        let end_offset = self.end.to_offset(snapshot);
24627        if start_offset == end_offset {
24628            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
24629        } else {
24630            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
24631        }
24632    }
24633}
24634
24635pub trait RowExt {
24636    fn as_f64(&self) -> f64;
24637
24638    fn next_row(&self) -> Self;
24639
24640    fn previous_row(&self) -> Self;
24641
24642    fn minus(&self, other: Self) -> u32;
24643}
24644
24645impl RowExt for DisplayRow {
24646    fn as_f64(&self) -> f64 {
24647        self.0 as _
24648    }
24649
24650    fn next_row(&self) -> Self {
24651        Self(self.0 + 1)
24652    }
24653
24654    fn previous_row(&self) -> Self {
24655        Self(self.0.saturating_sub(1))
24656    }
24657
24658    fn minus(&self, other: Self) -> u32 {
24659        self.0 - other.0
24660    }
24661}
24662
24663impl RowExt for MultiBufferRow {
24664    fn as_f64(&self) -> f64 {
24665        self.0 as _
24666    }
24667
24668    fn next_row(&self) -> Self {
24669        Self(self.0 + 1)
24670    }
24671
24672    fn previous_row(&self) -> Self {
24673        Self(self.0.saturating_sub(1))
24674    }
24675
24676    fn minus(&self, other: Self) -> u32 {
24677        self.0 - other.0
24678    }
24679}
24680
24681trait RowRangeExt {
24682    type Row;
24683
24684    fn len(&self) -> usize;
24685
24686    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
24687}
24688
24689impl RowRangeExt for Range<MultiBufferRow> {
24690    type Row = MultiBufferRow;
24691
24692    fn len(&self) -> usize {
24693        (self.end.0 - self.start.0) as usize
24694    }
24695
24696    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
24697        (self.start.0..self.end.0).map(MultiBufferRow)
24698    }
24699}
24700
24701impl RowRangeExt for Range<DisplayRow> {
24702    type Row = DisplayRow;
24703
24704    fn len(&self) -> usize {
24705        (self.end.0 - self.start.0) as usize
24706    }
24707
24708    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
24709        (self.start.0..self.end.0).map(DisplayRow)
24710    }
24711}
24712
24713/// If select range has more than one line, we
24714/// just point the cursor to range.start.
24715fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
24716    if range.start.row == range.end.row {
24717        range
24718    } else {
24719        range.start..range.start
24720    }
24721}
24722pub struct KillRing(ClipboardItem);
24723impl Global for KillRing {}
24724
24725const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
24726
24727enum BreakpointPromptEditAction {
24728    Log,
24729    Condition,
24730    HitCondition,
24731}
24732
24733struct BreakpointPromptEditor {
24734    pub(crate) prompt: Entity<Editor>,
24735    editor: WeakEntity<Editor>,
24736    breakpoint_anchor: Anchor,
24737    breakpoint: Breakpoint,
24738    edit_action: BreakpointPromptEditAction,
24739    block_ids: HashSet<CustomBlockId>,
24740    editor_margins: Arc<Mutex<EditorMargins>>,
24741    _subscriptions: Vec<Subscription>,
24742}
24743
24744impl BreakpointPromptEditor {
24745    const MAX_LINES: u8 = 4;
24746
24747    fn new(
24748        editor: WeakEntity<Editor>,
24749        breakpoint_anchor: Anchor,
24750        breakpoint: Breakpoint,
24751        edit_action: BreakpointPromptEditAction,
24752        window: &mut Window,
24753        cx: &mut Context<Self>,
24754    ) -> Self {
24755        let base_text = match edit_action {
24756            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
24757            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
24758            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
24759        }
24760        .map(|msg| msg.to_string())
24761        .unwrap_or_default();
24762
24763        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
24764        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
24765
24766        let prompt = cx.new(|cx| {
24767            let mut prompt = Editor::new(
24768                EditorMode::AutoHeight {
24769                    min_lines: 1,
24770                    max_lines: Some(Self::MAX_LINES as usize),
24771                },
24772                buffer,
24773                None,
24774                window,
24775                cx,
24776            );
24777            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
24778            prompt.set_show_cursor_when_unfocused(false, cx);
24779            prompt.set_placeholder_text(
24780                match edit_action {
24781                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
24782                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
24783                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
24784                },
24785                window,
24786                cx,
24787            );
24788
24789            prompt
24790        });
24791
24792        Self {
24793            prompt,
24794            editor,
24795            breakpoint_anchor,
24796            breakpoint,
24797            edit_action,
24798            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
24799            block_ids: Default::default(),
24800            _subscriptions: vec![],
24801        }
24802    }
24803
24804    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
24805        self.block_ids.extend(block_ids)
24806    }
24807
24808    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
24809        if let Some(editor) = self.editor.upgrade() {
24810            let message = self
24811                .prompt
24812                .read(cx)
24813                .buffer
24814                .read(cx)
24815                .as_singleton()
24816                .expect("A multi buffer in breakpoint prompt isn't possible")
24817                .read(cx)
24818                .as_rope()
24819                .to_string();
24820
24821            editor.update(cx, |editor, cx| {
24822                editor.edit_breakpoint_at_anchor(
24823                    self.breakpoint_anchor,
24824                    self.breakpoint.clone(),
24825                    match self.edit_action {
24826                        BreakpointPromptEditAction::Log => {
24827                            BreakpointEditAction::EditLogMessage(message.into())
24828                        }
24829                        BreakpointPromptEditAction::Condition => {
24830                            BreakpointEditAction::EditCondition(message.into())
24831                        }
24832                        BreakpointPromptEditAction::HitCondition => {
24833                            BreakpointEditAction::EditHitCondition(message.into())
24834                        }
24835                    },
24836                    cx,
24837                );
24838
24839                editor.remove_blocks(self.block_ids.clone(), None, cx);
24840                cx.focus_self(window);
24841            });
24842        }
24843    }
24844
24845    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
24846        self.editor
24847            .update(cx, |editor, cx| {
24848                editor.remove_blocks(self.block_ids.clone(), None, cx);
24849                window.focus(&editor.focus_handle);
24850            })
24851            .log_err();
24852    }
24853
24854    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
24855        let settings = ThemeSettings::get_global(cx);
24856        let text_style = TextStyle {
24857            color: if self.prompt.read(cx).read_only(cx) {
24858                cx.theme().colors().text_disabled
24859            } else {
24860                cx.theme().colors().text
24861            },
24862            font_family: settings.buffer_font.family.clone(),
24863            font_fallbacks: settings.buffer_font.fallbacks.clone(),
24864            font_size: settings.buffer_font_size(cx).into(),
24865            font_weight: settings.buffer_font.weight,
24866            line_height: relative(settings.buffer_line_height.value()),
24867            ..Default::default()
24868        };
24869        EditorElement::new(
24870            &self.prompt,
24871            EditorStyle {
24872                background: cx.theme().colors().editor_background,
24873                local_player: cx.theme().players().local(),
24874                text: text_style,
24875                ..Default::default()
24876            },
24877        )
24878    }
24879}
24880
24881impl Render for BreakpointPromptEditor {
24882    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
24883        let editor_margins = *self.editor_margins.lock();
24884        let gutter_dimensions = editor_margins.gutter;
24885        h_flex()
24886            .key_context("Editor")
24887            .bg(cx.theme().colors().editor_background)
24888            .border_y_1()
24889            .border_color(cx.theme().status().info_border)
24890            .size_full()
24891            .py(window.line_height() / 2.5)
24892            .on_action(cx.listener(Self::confirm))
24893            .on_action(cx.listener(Self::cancel))
24894            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
24895            .child(div().flex_1().child(self.render_prompt_editor(cx)))
24896    }
24897}
24898
24899impl Focusable for BreakpointPromptEditor {
24900    fn focus_handle(&self, cx: &App) -> FocusHandle {
24901        self.prompt.focus_handle(cx)
24902    }
24903}
24904
24905fn all_edits_insertions_or_deletions(
24906    edits: &Vec<(Range<Anchor>, Arc<str>)>,
24907    snapshot: &MultiBufferSnapshot,
24908) -> bool {
24909    let mut all_insertions = true;
24910    let mut all_deletions = true;
24911
24912    for (range, new_text) in edits.iter() {
24913        let range_is_empty = range.to_offset(snapshot).is_empty();
24914        let text_is_empty = new_text.is_empty();
24915
24916        if range_is_empty != text_is_empty {
24917            if range_is_empty {
24918                all_deletions = false;
24919            } else {
24920                all_insertions = false;
24921            }
24922        } else {
24923            return false;
24924        }
24925
24926        if !all_insertions && !all_deletions {
24927            return false;
24928        }
24929    }
24930    all_insertions || all_deletions
24931}
24932
24933struct MissingEditPredictionKeybindingTooltip;
24934
24935impl Render for MissingEditPredictionKeybindingTooltip {
24936    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
24937        ui::tooltip_container(cx, |container, cx| {
24938            container
24939                .flex_shrink_0()
24940                .max_w_80()
24941                .min_h(rems_from_px(124.))
24942                .justify_between()
24943                .child(
24944                    v_flex()
24945                        .flex_1()
24946                        .text_ui_sm(cx)
24947                        .child(Label::new("Conflict with Accept Keybinding"))
24948                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
24949                )
24950                .child(
24951                    h_flex()
24952                        .pb_1()
24953                        .gap_1()
24954                        .items_end()
24955                        .w_full()
24956                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
24957                            window.dispatch_action(zed_actions::OpenKeymapFile.boxed_clone(), cx)
24958                        }))
24959                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
24960                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
24961                        })),
24962                )
24963        })
24964    }
24965}
24966
24967#[derive(Debug, Clone, Copy, PartialEq)]
24968pub struct LineHighlight {
24969    pub background: Background,
24970    pub border: Option<gpui::Hsla>,
24971    pub include_gutter: bool,
24972    pub type_id: Option<TypeId>,
24973}
24974
24975struct LineManipulationResult {
24976    pub new_text: String,
24977    pub line_count_before: usize,
24978    pub line_count_after: usize,
24979}
24980
24981fn render_diff_hunk_controls(
24982    row: u32,
24983    status: &DiffHunkStatus,
24984    hunk_range: Range<Anchor>,
24985    is_created_file: bool,
24986    line_height: Pixels,
24987    editor: &Entity<Editor>,
24988    _window: &mut Window,
24989    cx: &mut App,
24990) -> AnyElement {
24991    h_flex()
24992        .h(line_height)
24993        .mr_1()
24994        .gap_1()
24995        .px_0p5()
24996        .pb_1()
24997        .border_x_1()
24998        .border_b_1()
24999        .border_color(cx.theme().colors().border_variant)
25000        .rounded_b_lg()
25001        .bg(cx.theme().colors().editor_background)
25002        .gap_1()
25003        .block_mouse_except_scroll()
25004        .shadow_md()
25005        .child(if status.has_secondary_hunk() {
25006            Button::new(("stage", row as u64), "Stage")
25007                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
25008                .tooltip({
25009                    let focus_handle = editor.focus_handle(cx);
25010                    move |_window, cx| {
25011                        Tooltip::for_action_in(
25012                            "Stage Hunk",
25013                            &::git::ToggleStaged,
25014                            &focus_handle,
25015                            cx,
25016                        )
25017                    }
25018                })
25019                .on_click({
25020                    let editor = editor.clone();
25021                    move |_event, _window, cx| {
25022                        editor.update(cx, |editor, cx| {
25023                            editor.stage_or_unstage_diff_hunks(
25024                                true,
25025                                vec![hunk_range.start..hunk_range.start],
25026                                cx,
25027                            );
25028                        });
25029                    }
25030                })
25031        } else {
25032            Button::new(("unstage", row as u64), "Unstage")
25033                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
25034                .tooltip({
25035                    let focus_handle = editor.focus_handle(cx);
25036                    move |_window, cx| {
25037                        Tooltip::for_action_in(
25038                            "Unstage Hunk",
25039                            &::git::ToggleStaged,
25040                            &focus_handle,
25041                            cx,
25042                        )
25043                    }
25044                })
25045                .on_click({
25046                    let editor = editor.clone();
25047                    move |_event, _window, cx| {
25048                        editor.update(cx, |editor, cx| {
25049                            editor.stage_or_unstage_diff_hunks(
25050                                false,
25051                                vec![hunk_range.start..hunk_range.start],
25052                                cx,
25053                            );
25054                        });
25055                    }
25056                })
25057        })
25058        .child(
25059            Button::new(("restore", row as u64), "Restore")
25060                .tooltip({
25061                    let focus_handle = editor.focus_handle(cx);
25062                    move |_window, cx| {
25063                        Tooltip::for_action_in("Restore Hunk", &::git::Restore, &focus_handle, cx)
25064                    }
25065                })
25066                .on_click({
25067                    let editor = editor.clone();
25068                    move |_event, window, cx| {
25069                        editor.update(cx, |editor, cx| {
25070                            let snapshot = editor.snapshot(window, cx);
25071                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot());
25072                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
25073                        });
25074                    }
25075                })
25076                .disabled(is_created_file),
25077        )
25078        .when(
25079            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
25080            |el| {
25081                el.child(
25082                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
25083                        .shape(IconButtonShape::Square)
25084                        .icon_size(IconSize::Small)
25085                        // .disabled(!has_multiple_hunks)
25086                        .tooltip({
25087                            let focus_handle = editor.focus_handle(cx);
25088                            move |_window, cx| {
25089                                Tooltip::for_action_in("Next Hunk", &GoToHunk, &focus_handle, cx)
25090                            }
25091                        })
25092                        .on_click({
25093                            let editor = editor.clone();
25094                            move |_event, window, cx| {
25095                                editor.update(cx, |editor, cx| {
25096                                    let snapshot = editor.snapshot(window, cx);
25097                                    let position =
25098                                        hunk_range.end.to_point(&snapshot.buffer_snapshot());
25099                                    editor.go_to_hunk_before_or_after_position(
25100                                        &snapshot,
25101                                        position,
25102                                        Direction::Next,
25103                                        window,
25104                                        cx,
25105                                    );
25106                                    editor.expand_selected_diff_hunks(cx);
25107                                });
25108                            }
25109                        }),
25110                )
25111                .child(
25112                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
25113                        .shape(IconButtonShape::Square)
25114                        .icon_size(IconSize::Small)
25115                        // .disabled(!has_multiple_hunks)
25116                        .tooltip({
25117                            let focus_handle = editor.focus_handle(cx);
25118                            move |_window, cx| {
25119                                Tooltip::for_action_in(
25120                                    "Previous Hunk",
25121                                    &GoToPreviousHunk,
25122                                    &focus_handle,
25123                                    cx,
25124                                )
25125                            }
25126                        })
25127                        .on_click({
25128                            let editor = editor.clone();
25129                            move |_event, window, cx| {
25130                                editor.update(cx, |editor, cx| {
25131                                    let snapshot = editor.snapshot(window, cx);
25132                                    let point =
25133                                        hunk_range.start.to_point(&snapshot.buffer_snapshot());
25134                                    editor.go_to_hunk_before_or_after_position(
25135                                        &snapshot,
25136                                        point,
25137                                        Direction::Prev,
25138                                        window,
25139                                        cx,
25140                                    );
25141                                    editor.expand_selected_diff_hunks(cx);
25142                                });
25143                            }
25144                        }),
25145                )
25146            },
25147        )
25148        .into_any_element()
25149}
25150
25151pub fn multibuffer_context_lines(cx: &App) -> u32 {
25152    EditorSettings::try_get(cx)
25153        .map(|settings| settings.excerpt_context_lines)
25154        .unwrap_or(2)
25155        .min(32)
25156}