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    collapse_matches: bool,
 1100    autoindent_mode: Option<AutoindentMode>,
 1101    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
 1102    input_enabled: bool,
 1103    use_modal_editing: bool,
 1104    read_only: bool,
 1105    leader_id: Option<CollaboratorId>,
 1106    remote_id: Option<ViewId>,
 1107    pub hover_state: HoverState,
 1108    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
 1109    gutter_hovered: bool,
 1110    hovered_link_state: Option<HoveredLinkState>,
 1111    edit_prediction_provider: Option<RegisteredEditPredictionProvider>,
 1112    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
 1113    active_edit_prediction: Option<EditPredictionState>,
 1114    /// Used to prevent flickering as the user types while the menu is open
 1115    stale_edit_prediction_in_menu: Option<EditPredictionState>,
 1116    edit_prediction_settings: EditPredictionSettings,
 1117    edit_predictions_hidden_for_vim_mode: bool,
 1118    show_edit_predictions_override: Option<bool>,
 1119    menu_edit_predictions_policy: MenuEditPredictionsPolicy,
 1120    edit_prediction_preview: EditPredictionPreview,
 1121    edit_prediction_indent_conflict: bool,
 1122    edit_prediction_requires_modifier_in_indent_conflict: bool,
 1123    next_inlay_id: usize,
 1124    next_color_inlay_id: usize,
 1125    _subscriptions: Vec<Subscription>,
 1126    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
 1127    gutter_dimensions: GutterDimensions,
 1128    style: Option<EditorStyle>,
 1129    text_style_refinement: Option<TextStyleRefinement>,
 1130    next_editor_action_id: EditorActionId,
 1131    editor_actions: Rc<
 1132        RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&Editor, &mut Window, &mut Context<Self>)>>>,
 1133    >,
 1134    use_autoclose: bool,
 1135    use_auto_surround: bool,
 1136    auto_replace_emoji_shortcode: bool,
 1137    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1138    show_git_blame_gutter: bool,
 1139    show_git_blame_inline: bool,
 1140    show_git_blame_inline_delay_task: Option<Task<()>>,
 1141    git_blame_inline_enabled: bool,
 1142    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1143    buffer_serialization: Option<BufferSerialization>,
 1144    show_selection_menu: Option<bool>,
 1145    blame: Option<Entity<GitBlame>>,
 1146    blame_subscription: Option<Subscription>,
 1147    custom_context_menu: Option<
 1148        Box<
 1149            dyn 'static
 1150                + Fn(
 1151                    &mut Self,
 1152                    DisplayPoint,
 1153                    &mut Window,
 1154                    &mut Context<Self>,
 1155                ) -> Option<Entity<ui::ContextMenu>>,
 1156        >,
 1157    >,
 1158    last_bounds: Option<Bounds<Pixels>>,
 1159    last_position_map: Option<Rc<PositionMap>>,
 1160    expect_bounds_change: Option<Bounds<Pixels>>,
 1161    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
 1162    tasks_update_task: Option<Task<()>>,
 1163    breakpoint_store: Option<Entity<BreakpointStore>>,
 1164    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1165    hovered_diff_hunk_row: Option<DisplayRow>,
 1166    pull_diagnostics_task: Task<()>,
 1167    in_project_search: bool,
 1168    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1169    breadcrumb_header: Option<String>,
 1170    focused_block: Option<FocusedBlock>,
 1171    next_scroll_position: NextScrollCursorCenterTopBottom,
 1172    addons: HashMap<TypeId, Box<dyn Addon>>,
 1173    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1174    load_diff_task: Option<Shared<Task<()>>>,
 1175    /// Whether we are temporarily displaying a diff other than git's
 1176    temporary_diff_override: bool,
 1177    selection_mark_mode: bool,
 1178    toggle_fold_multiple_buffers: Task<()>,
 1179    _scroll_cursor_center_top_bottom_task: Task<()>,
 1180    serialize_selections: Task<()>,
 1181    serialize_folds: Task<()>,
 1182    mouse_cursor_hidden: bool,
 1183    minimap: Option<Entity<Self>>,
 1184    hide_mouse_mode: HideMouseMode,
 1185    pub change_list: ChangeList,
 1186    inline_value_cache: InlineValueCache,
 1187
 1188    selection_drag_state: SelectionDragState,
 1189    colors: Option<LspColorData>,
 1190    post_scroll_update: Task<()>,
 1191    refresh_colors_task: Task<()>,
 1192    inlay_hints: Option<LspInlayHintData>,
 1193    folding_newlines: Task<()>,
 1194    select_next_is_case_sensitive: Option<bool>,
 1195    pub lookup_key: Option<Box<dyn Any + Send + Sync>>,
 1196}
 1197
 1198fn debounce_value(debounce_ms: u64) -> Option<Duration> {
 1199    if debounce_ms > 0 {
 1200        Some(Duration::from_millis(debounce_ms))
 1201    } else {
 1202        None
 1203    }
 1204}
 1205
 1206#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1207enum NextScrollCursorCenterTopBottom {
 1208    #[default]
 1209    Center,
 1210    Top,
 1211    Bottom,
 1212}
 1213
 1214impl NextScrollCursorCenterTopBottom {
 1215    fn next(&self) -> Self {
 1216        match self {
 1217            Self::Center => Self::Top,
 1218            Self::Top => Self::Bottom,
 1219            Self::Bottom => Self::Center,
 1220        }
 1221    }
 1222}
 1223
 1224#[derive(Clone)]
 1225pub struct EditorSnapshot {
 1226    pub mode: EditorMode,
 1227    show_gutter: bool,
 1228    show_line_numbers: Option<bool>,
 1229    show_git_diff_gutter: Option<bool>,
 1230    show_code_actions: Option<bool>,
 1231    show_runnables: Option<bool>,
 1232    show_breakpoints: Option<bool>,
 1233    git_blame_gutter_max_author_length: Option<usize>,
 1234    pub display_snapshot: DisplaySnapshot,
 1235    pub placeholder_display_snapshot: Option<DisplaySnapshot>,
 1236    is_focused: bool,
 1237    scroll_anchor: ScrollAnchor,
 1238    ongoing_scroll: OngoingScroll,
 1239    current_line_highlight: CurrentLineHighlight,
 1240    gutter_hovered: bool,
 1241}
 1242
 1243#[derive(Default, Debug, Clone, Copy)]
 1244pub struct GutterDimensions {
 1245    pub left_padding: Pixels,
 1246    pub right_padding: Pixels,
 1247    pub width: Pixels,
 1248    pub margin: Pixels,
 1249    pub git_blame_entries_width: Option<Pixels>,
 1250}
 1251
 1252impl GutterDimensions {
 1253    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1254        Self {
 1255            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1256            ..Default::default()
 1257        }
 1258    }
 1259
 1260    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1261        -cx.text_system().descent(font_id, font_size)
 1262    }
 1263    /// The full width of the space taken up by the gutter.
 1264    pub fn full_width(&self) -> Pixels {
 1265        self.margin + self.width
 1266    }
 1267
 1268    /// The width of the space reserved for the fold indicators,
 1269    /// use alongside 'justify_end' and `gutter_width` to
 1270    /// right align content with the line numbers
 1271    pub fn fold_area_width(&self) -> Pixels {
 1272        self.margin + self.right_padding
 1273    }
 1274}
 1275
 1276struct CharacterDimensions {
 1277    em_width: Pixels,
 1278    em_advance: Pixels,
 1279    line_height: Pixels,
 1280}
 1281
 1282#[derive(Debug)]
 1283pub struct RemoteSelection {
 1284    pub replica_id: ReplicaId,
 1285    pub selection: Selection<Anchor>,
 1286    pub cursor_shape: CursorShape,
 1287    pub collaborator_id: CollaboratorId,
 1288    pub line_mode: bool,
 1289    pub user_name: Option<SharedString>,
 1290    pub color: PlayerColor,
 1291}
 1292
 1293#[derive(Clone, Debug)]
 1294struct SelectionHistoryEntry {
 1295    selections: Arc<[Selection<Anchor>]>,
 1296    select_next_state: Option<SelectNextState>,
 1297    select_prev_state: Option<SelectNextState>,
 1298    add_selections_state: Option<AddSelectionsState>,
 1299}
 1300
 1301#[derive(Copy, Clone, Debug, PartialEq, Eq)]
 1302enum SelectionHistoryMode {
 1303    Normal,
 1304    Undoing,
 1305    Redoing,
 1306    Skipping,
 1307}
 1308
 1309#[derive(Clone, PartialEq, Eq, Hash)]
 1310struct HoveredCursor {
 1311    replica_id: ReplicaId,
 1312    selection_id: usize,
 1313}
 1314
 1315impl Default for SelectionHistoryMode {
 1316    fn default() -> Self {
 1317        Self::Normal
 1318    }
 1319}
 1320
 1321#[derive(Debug)]
 1322/// SelectionEffects controls the side-effects of updating the selection.
 1323///
 1324/// The default behaviour does "what you mostly want":
 1325/// - it pushes to the nav history if the cursor moved by >10 lines
 1326/// - it re-triggers completion requests
 1327/// - it scrolls to fit
 1328///
 1329/// You might want to modify these behaviours. For example when doing a "jump"
 1330/// like go to definition, we always want to add to nav history; but when scrolling
 1331/// in vim mode we never do.
 1332///
 1333/// Similarly, you might want to disable scrolling if you don't want the viewport to
 1334/// move.
 1335#[derive(Clone)]
 1336pub struct SelectionEffects {
 1337    nav_history: Option<bool>,
 1338    completions: bool,
 1339    scroll: Option<Autoscroll>,
 1340}
 1341
 1342impl Default for SelectionEffects {
 1343    fn default() -> Self {
 1344        Self {
 1345            nav_history: None,
 1346            completions: true,
 1347            scroll: Some(Autoscroll::fit()),
 1348        }
 1349    }
 1350}
 1351impl SelectionEffects {
 1352    pub fn scroll(scroll: Autoscroll) -> Self {
 1353        Self {
 1354            scroll: Some(scroll),
 1355            ..Default::default()
 1356        }
 1357    }
 1358
 1359    pub fn no_scroll() -> Self {
 1360        Self {
 1361            scroll: None,
 1362            ..Default::default()
 1363        }
 1364    }
 1365
 1366    pub fn completions(self, completions: bool) -> Self {
 1367        Self {
 1368            completions,
 1369            ..self
 1370        }
 1371    }
 1372
 1373    pub fn nav_history(self, nav_history: bool) -> Self {
 1374        Self {
 1375            nav_history: Some(nav_history),
 1376            ..self
 1377        }
 1378    }
 1379}
 1380
 1381struct DeferredSelectionEffectsState {
 1382    changed: bool,
 1383    effects: SelectionEffects,
 1384    old_cursor_position: Anchor,
 1385    history_entry: SelectionHistoryEntry,
 1386}
 1387
 1388#[derive(Default)]
 1389struct SelectionHistory {
 1390    #[allow(clippy::type_complexity)]
 1391    selections_by_transaction:
 1392        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1393    mode: SelectionHistoryMode,
 1394    undo_stack: VecDeque<SelectionHistoryEntry>,
 1395    redo_stack: VecDeque<SelectionHistoryEntry>,
 1396}
 1397
 1398impl SelectionHistory {
 1399    #[track_caller]
 1400    fn insert_transaction(
 1401        &mut self,
 1402        transaction_id: TransactionId,
 1403        selections: Arc<[Selection<Anchor>]>,
 1404    ) {
 1405        if selections.is_empty() {
 1406            log::error!(
 1407                "SelectionHistory::insert_transaction called with empty selections. Caller: {}",
 1408                std::panic::Location::caller()
 1409            );
 1410            return;
 1411        }
 1412        self.selections_by_transaction
 1413            .insert(transaction_id, (selections, None));
 1414    }
 1415
 1416    #[allow(clippy::type_complexity)]
 1417    fn transaction(
 1418        &self,
 1419        transaction_id: TransactionId,
 1420    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1421        self.selections_by_transaction.get(&transaction_id)
 1422    }
 1423
 1424    #[allow(clippy::type_complexity)]
 1425    fn transaction_mut(
 1426        &mut self,
 1427        transaction_id: TransactionId,
 1428    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1429        self.selections_by_transaction.get_mut(&transaction_id)
 1430    }
 1431
 1432    fn push(&mut self, entry: SelectionHistoryEntry) {
 1433        if !entry.selections.is_empty() {
 1434            match self.mode {
 1435                SelectionHistoryMode::Normal => {
 1436                    self.push_undo(entry);
 1437                    self.redo_stack.clear();
 1438                }
 1439                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1440                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1441                SelectionHistoryMode::Skipping => {}
 1442            }
 1443        }
 1444    }
 1445
 1446    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1447        if self
 1448            .undo_stack
 1449            .back()
 1450            .is_none_or(|e| e.selections != entry.selections)
 1451        {
 1452            self.undo_stack.push_back(entry);
 1453            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1454                self.undo_stack.pop_front();
 1455            }
 1456        }
 1457    }
 1458
 1459    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1460        if self
 1461            .redo_stack
 1462            .back()
 1463            .is_none_or(|e| e.selections != entry.selections)
 1464        {
 1465            self.redo_stack.push_back(entry);
 1466            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1467                self.redo_stack.pop_front();
 1468            }
 1469        }
 1470    }
 1471}
 1472
 1473#[derive(Clone, Copy)]
 1474pub struct RowHighlightOptions {
 1475    pub autoscroll: bool,
 1476    pub include_gutter: bool,
 1477}
 1478
 1479impl Default for RowHighlightOptions {
 1480    fn default() -> Self {
 1481        Self {
 1482            autoscroll: Default::default(),
 1483            include_gutter: true,
 1484        }
 1485    }
 1486}
 1487
 1488struct RowHighlight {
 1489    index: usize,
 1490    range: Range<Anchor>,
 1491    color: Hsla,
 1492    options: RowHighlightOptions,
 1493    type_id: TypeId,
 1494}
 1495
 1496#[derive(Clone, Debug)]
 1497struct AddSelectionsState {
 1498    groups: Vec<AddSelectionsGroup>,
 1499}
 1500
 1501#[derive(Clone, Debug)]
 1502struct AddSelectionsGroup {
 1503    above: bool,
 1504    stack: Vec<usize>,
 1505}
 1506
 1507#[derive(Clone)]
 1508struct SelectNextState {
 1509    query: AhoCorasick,
 1510    wordwise: bool,
 1511    done: bool,
 1512}
 1513
 1514impl std::fmt::Debug for SelectNextState {
 1515    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1516        f.debug_struct(std::any::type_name::<Self>())
 1517            .field("wordwise", &self.wordwise)
 1518            .field("done", &self.done)
 1519            .finish()
 1520    }
 1521}
 1522
 1523#[derive(Debug)]
 1524struct AutocloseRegion {
 1525    selection_id: usize,
 1526    range: Range<Anchor>,
 1527    pair: BracketPair,
 1528}
 1529
 1530#[derive(Debug)]
 1531struct SnippetState {
 1532    ranges: Vec<Vec<Range<Anchor>>>,
 1533    active_index: usize,
 1534    choices: Vec<Option<Vec<String>>>,
 1535}
 1536
 1537#[doc(hidden)]
 1538pub struct RenameState {
 1539    pub range: Range<Anchor>,
 1540    pub old_name: Arc<str>,
 1541    pub editor: Entity<Editor>,
 1542    block_id: CustomBlockId,
 1543}
 1544
 1545struct InvalidationStack<T>(Vec<T>);
 1546
 1547struct RegisteredEditPredictionProvider {
 1548    provider: Arc<dyn EditPredictionProviderHandle>,
 1549    _subscription: Subscription,
 1550}
 1551
 1552#[derive(Debug, PartialEq, Eq)]
 1553pub struct ActiveDiagnosticGroup {
 1554    pub active_range: Range<Anchor>,
 1555    pub active_message: String,
 1556    pub group_id: usize,
 1557    pub blocks: HashSet<CustomBlockId>,
 1558}
 1559
 1560#[derive(Debug, PartialEq, Eq)]
 1561
 1562pub(crate) enum ActiveDiagnostic {
 1563    None,
 1564    All,
 1565    Group(ActiveDiagnosticGroup),
 1566}
 1567
 1568#[derive(Serialize, Deserialize, Clone, Debug)]
 1569pub struct ClipboardSelection {
 1570    /// The number of bytes in this selection.
 1571    pub len: usize,
 1572    /// Whether this was a full-line selection.
 1573    pub is_entire_line: bool,
 1574    /// The indentation of the first line when this content was originally copied.
 1575    pub first_line_indent: u32,
 1576}
 1577
 1578// selections, scroll behavior, was newest selection reversed
 1579type SelectSyntaxNodeHistoryState = (
 1580    Box<[Selection<usize>]>,
 1581    SelectSyntaxNodeScrollBehavior,
 1582    bool,
 1583);
 1584
 1585#[derive(Default)]
 1586struct SelectSyntaxNodeHistory {
 1587    stack: Vec<SelectSyntaxNodeHistoryState>,
 1588    // disable temporarily to allow changing selections without losing the stack
 1589    pub disable_clearing: bool,
 1590}
 1591
 1592impl SelectSyntaxNodeHistory {
 1593    pub fn try_clear(&mut self) {
 1594        if !self.disable_clearing {
 1595            self.stack.clear();
 1596        }
 1597    }
 1598
 1599    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1600        self.stack.push(selection);
 1601    }
 1602
 1603    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1604        self.stack.pop()
 1605    }
 1606}
 1607
 1608enum SelectSyntaxNodeScrollBehavior {
 1609    CursorTop,
 1610    FitSelection,
 1611    CursorBottom,
 1612}
 1613
 1614#[derive(Debug)]
 1615pub(crate) struct NavigationData {
 1616    cursor_anchor: Anchor,
 1617    cursor_position: Point,
 1618    scroll_anchor: ScrollAnchor,
 1619    scroll_top_row: u32,
 1620}
 1621
 1622#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1623pub enum GotoDefinitionKind {
 1624    Symbol,
 1625    Declaration,
 1626    Type,
 1627    Implementation,
 1628}
 1629
 1630pub enum FormatTarget {
 1631    Buffers(HashSet<Entity<Buffer>>),
 1632    Ranges(Vec<Range<MultiBufferPoint>>),
 1633}
 1634
 1635pub(crate) struct FocusedBlock {
 1636    id: BlockId,
 1637    focus_handle: WeakFocusHandle,
 1638}
 1639
 1640#[derive(Clone)]
 1641enum JumpData {
 1642    MultiBufferRow {
 1643        row: MultiBufferRow,
 1644        line_offset_from_top: u32,
 1645    },
 1646    MultiBufferPoint {
 1647        excerpt_id: ExcerptId,
 1648        position: Point,
 1649        anchor: text::Anchor,
 1650        line_offset_from_top: u32,
 1651    },
 1652}
 1653
 1654pub enum MultibufferSelectionMode {
 1655    First,
 1656    All,
 1657}
 1658
 1659#[derive(Clone, Copy, Debug, Default)]
 1660pub struct RewrapOptions {
 1661    pub override_language_settings: bool,
 1662    pub preserve_existing_whitespace: bool,
 1663}
 1664
 1665impl Editor {
 1666    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1667        let buffer = cx.new(|cx| Buffer::local("", cx));
 1668        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1669        Self::new(EditorMode::SingleLine, buffer, None, window, cx)
 1670    }
 1671
 1672    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1673        let buffer = cx.new(|cx| Buffer::local("", cx));
 1674        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1675        Self::new(EditorMode::full(), buffer, None, window, cx)
 1676    }
 1677
 1678    pub fn auto_height(
 1679        min_lines: usize,
 1680        max_lines: usize,
 1681        window: &mut Window,
 1682        cx: &mut Context<Self>,
 1683    ) -> Self {
 1684        let buffer = cx.new(|cx| Buffer::local("", cx));
 1685        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1686        Self::new(
 1687            EditorMode::AutoHeight {
 1688                min_lines,
 1689                max_lines: Some(max_lines),
 1690            },
 1691            buffer,
 1692            None,
 1693            window,
 1694            cx,
 1695        )
 1696    }
 1697
 1698    /// Creates a new auto-height editor with a minimum number of lines but no maximum.
 1699    /// The editor grows as tall as needed to fit its content.
 1700    pub fn auto_height_unbounded(
 1701        min_lines: usize,
 1702        window: &mut Window,
 1703        cx: &mut Context<Self>,
 1704    ) -> Self {
 1705        let buffer = cx.new(|cx| Buffer::local("", cx));
 1706        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1707        Self::new(
 1708            EditorMode::AutoHeight {
 1709                min_lines,
 1710                max_lines: None,
 1711            },
 1712            buffer,
 1713            None,
 1714            window,
 1715            cx,
 1716        )
 1717    }
 1718
 1719    pub fn for_buffer(
 1720        buffer: Entity<Buffer>,
 1721        project: Option<Entity<Project>>,
 1722        window: &mut Window,
 1723        cx: &mut Context<Self>,
 1724    ) -> Self {
 1725        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1726        Self::new(EditorMode::full(), buffer, project, window, cx)
 1727    }
 1728
 1729    pub fn for_multibuffer(
 1730        buffer: Entity<MultiBuffer>,
 1731        project: Option<Entity<Project>>,
 1732        window: &mut Window,
 1733        cx: &mut Context<Self>,
 1734    ) -> Self {
 1735        Self::new(EditorMode::full(), buffer, project, window, cx)
 1736    }
 1737
 1738    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1739        let mut clone = Self::new(
 1740            self.mode.clone(),
 1741            self.buffer.clone(),
 1742            self.project.clone(),
 1743            window,
 1744            cx,
 1745        );
 1746        self.display_map.update(cx, |display_map, cx| {
 1747            let snapshot = display_map.snapshot(cx);
 1748            clone.display_map.update(cx, |display_map, cx| {
 1749                display_map.set_state(&snapshot, cx);
 1750            });
 1751        });
 1752        clone.folds_did_change(cx);
 1753        clone.selections.clone_state(&self.selections);
 1754        clone.scroll_manager.clone_state(&self.scroll_manager);
 1755        clone.searchable = self.searchable;
 1756        clone.read_only = self.read_only;
 1757        clone
 1758    }
 1759
 1760    pub fn new(
 1761        mode: EditorMode,
 1762        buffer: Entity<MultiBuffer>,
 1763        project: Option<Entity<Project>>,
 1764        window: &mut Window,
 1765        cx: &mut Context<Self>,
 1766    ) -> Self {
 1767        Editor::new_internal(mode, buffer, project, None, window, cx)
 1768    }
 1769
 1770    pub fn sticky_headers(&self, cx: &App) -> Option<Vec<OutlineItem<Anchor>>> {
 1771        let multi_buffer = self.buffer().read(cx);
 1772        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 1773        let multi_buffer_visible_start = self
 1774            .scroll_manager
 1775            .anchor()
 1776            .anchor
 1777            .to_point(&multi_buffer_snapshot);
 1778        let max_row = multi_buffer_snapshot.max_point().row;
 1779
 1780        let start_row = (multi_buffer_visible_start.row).min(max_row);
 1781        let end_row = (multi_buffer_visible_start.row + 10).min(max_row);
 1782
 1783        if let Some((excerpt_id, buffer_id, buffer)) = multi_buffer.read(cx).as_singleton() {
 1784            let outline_items = buffer
 1785                .outline_items_containing(
 1786                    Point::new(start_row, 0)..Point::new(end_row, 0),
 1787                    true,
 1788                    self.style().map(|style| style.syntax.as_ref()),
 1789                )
 1790                .into_iter()
 1791                .map(|outline_item| OutlineItem {
 1792                    depth: outline_item.depth,
 1793                    range: Anchor::range_in_buffer(*excerpt_id, buffer_id, outline_item.range),
 1794                    source_range_for_text: Anchor::range_in_buffer(
 1795                        *excerpt_id,
 1796                        buffer_id,
 1797                        outline_item.source_range_for_text,
 1798                    ),
 1799                    text: outline_item.text,
 1800                    highlight_ranges: outline_item.highlight_ranges,
 1801                    name_ranges: outline_item.name_ranges,
 1802                    body_range: outline_item
 1803                        .body_range
 1804                        .map(|range| Anchor::range_in_buffer(*excerpt_id, buffer_id, range)),
 1805                    annotation_range: outline_item
 1806                        .annotation_range
 1807                        .map(|range| Anchor::range_in_buffer(*excerpt_id, buffer_id, range)),
 1808                });
 1809            return Some(outline_items.collect());
 1810        }
 1811
 1812        None
 1813    }
 1814
 1815    fn new_internal(
 1816        mode: EditorMode,
 1817        multi_buffer: Entity<MultiBuffer>,
 1818        project: Option<Entity<Project>>,
 1819        display_map: Option<Entity<DisplayMap>>,
 1820        window: &mut Window,
 1821        cx: &mut Context<Self>,
 1822    ) -> Self {
 1823        debug_assert!(
 1824            display_map.is_none() || mode.is_minimap(),
 1825            "Providing a display map for a new editor is only intended for the minimap and might have unintended side effects otherwise!"
 1826        );
 1827
 1828        let full_mode = mode.is_full();
 1829        let is_minimap = mode.is_minimap();
 1830        let diagnostics_max_severity = if full_mode {
 1831            EditorSettings::get_global(cx)
 1832                .diagnostics_max_severity
 1833                .unwrap_or(DiagnosticSeverity::Hint)
 1834        } else {
 1835            DiagnosticSeverity::Off
 1836        };
 1837        let style = window.text_style();
 1838        let font_size = style.font_size.to_pixels(window.rem_size());
 1839        let editor = cx.entity().downgrade();
 1840        let fold_placeholder = FoldPlaceholder {
 1841            constrain_width: false,
 1842            render: Arc::new(move |fold_id, fold_range, cx| {
 1843                let editor = editor.clone();
 1844                div()
 1845                    .id(fold_id)
 1846                    .bg(cx.theme().colors().ghost_element_background)
 1847                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1848                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1849                    .rounded_xs()
 1850                    .size_full()
 1851                    .cursor_pointer()
 1852                    .child("")
 1853                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1854                    .on_click(move |_, _window, cx| {
 1855                        editor
 1856                            .update(cx, |editor, cx| {
 1857                                editor.unfold_ranges(
 1858                                    &[fold_range.start..fold_range.end],
 1859                                    true,
 1860                                    false,
 1861                                    cx,
 1862                                );
 1863                                cx.stop_propagation();
 1864                            })
 1865                            .ok();
 1866                    })
 1867                    .into_any()
 1868            }),
 1869            merge_adjacent: true,
 1870            ..FoldPlaceholder::default()
 1871        };
 1872        let display_map = display_map.unwrap_or_else(|| {
 1873            cx.new(|cx| {
 1874                DisplayMap::new(
 1875                    multi_buffer.clone(),
 1876                    style.font(),
 1877                    font_size,
 1878                    None,
 1879                    FILE_HEADER_HEIGHT,
 1880                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1881                    fold_placeholder,
 1882                    diagnostics_max_severity,
 1883                    cx,
 1884                )
 1885            })
 1886        });
 1887
 1888        let selections = SelectionsCollection::new();
 1889
 1890        let blink_manager = cx.new(|cx| {
 1891            let mut blink_manager = BlinkManager::new(CURSOR_BLINK_INTERVAL, cx);
 1892            if is_minimap {
 1893                blink_manager.disable(cx);
 1894            }
 1895            blink_manager
 1896        });
 1897
 1898        let soft_wrap_mode_override =
 1899            matches!(mode, EditorMode::SingleLine).then(|| language_settings::SoftWrap::None);
 1900
 1901        let mut project_subscriptions = Vec::new();
 1902        if full_mode && let Some(project) = project.as_ref() {
 1903            project_subscriptions.push(cx.subscribe_in(
 1904                project,
 1905                window,
 1906                |editor, _, event, window, cx| match event {
 1907                    project::Event::RefreshCodeLens => {
 1908                        // we always query lens with actions, without storing them, always refreshing them
 1909                    }
 1910                    project::Event::RefreshInlayHints {
 1911                        server_id,
 1912                        request_id,
 1913                    } => {
 1914                        editor.refresh_inlay_hints(
 1915                            InlayHintRefreshReason::RefreshRequested {
 1916                                server_id: *server_id,
 1917                                request_id: *request_id,
 1918                            },
 1919                            cx,
 1920                        );
 1921                    }
 1922                    project::Event::LanguageServerRemoved(..) => {
 1923                        if editor.tasks_update_task.is_none() {
 1924                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1925                        }
 1926                        editor.registered_buffers.clear();
 1927                        editor.register_visible_buffers(cx);
 1928                    }
 1929                    project::Event::LanguageServerAdded(..) => {
 1930                        if editor.tasks_update_task.is_none() {
 1931                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1932                        }
 1933                    }
 1934                    project::Event::SnippetEdit(id, snippet_edits) => {
 1935                        if let Some(buffer) = editor.buffer.read(cx).buffer(*id) {
 1936                            let focus_handle = editor.focus_handle(cx);
 1937                            if focus_handle.is_focused(window) {
 1938                                let snapshot = buffer.read(cx).snapshot();
 1939                                for (range, snippet) in snippet_edits {
 1940                                    let editor_range =
 1941                                        language::range_from_lsp(*range).to_offset(&snapshot);
 1942                                    editor
 1943                                        .insert_snippet(
 1944                                            &[editor_range],
 1945                                            snippet.clone(),
 1946                                            window,
 1947                                            cx,
 1948                                        )
 1949                                        .ok();
 1950                                }
 1951                            }
 1952                        }
 1953                    }
 1954                    project::Event::LanguageServerBufferRegistered { buffer_id, .. } => {
 1955                        let buffer_id = *buffer_id;
 1956                        if editor.buffer().read(cx).buffer(buffer_id).is_some() {
 1957                            editor.register_buffer(buffer_id, cx);
 1958                            editor.update_lsp_data(Some(buffer_id), window, cx);
 1959                            editor.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
 1960                            refresh_linked_ranges(editor, window, cx);
 1961                            editor.refresh_code_actions(window, cx);
 1962                            editor.refresh_document_highlights(cx);
 1963                        }
 1964                    }
 1965
 1966                    project::Event::EntryRenamed(transaction, project_path, abs_path) => {
 1967                        let Some(workspace) = editor.workspace() else {
 1968                            return;
 1969                        };
 1970                        let Some(active_editor) = workspace.read(cx).active_item_as::<Self>(cx)
 1971                        else {
 1972                            return;
 1973                        };
 1974
 1975                        if active_editor.entity_id() == cx.entity_id() {
 1976                            let entity_id = cx.entity_id();
 1977                            workspace.update(cx, |this, cx| {
 1978                                this.panes_mut()
 1979                                    .iter_mut()
 1980                                    .filter(|pane| pane.entity_id() != entity_id)
 1981                                    .for_each(|p| {
 1982                                        p.update(cx, |pane, _| {
 1983                                            pane.nav_history_mut().rename_item(
 1984                                                entity_id,
 1985                                                project_path.clone(),
 1986                                                abs_path.clone().into(),
 1987                                            );
 1988                                        })
 1989                                    });
 1990                            });
 1991                            let edited_buffers_already_open = {
 1992                                let other_editors: Vec<Entity<Editor>> = workspace
 1993                                    .read(cx)
 1994                                    .panes()
 1995                                    .iter()
 1996                                    .flat_map(|pane| pane.read(cx).items_of_type::<Editor>())
 1997                                    .filter(|editor| editor.entity_id() != cx.entity_id())
 1998                                    .collect();
 1999
 2000                                transaction.0.keys().all(|buffer| {
 2001                                    other_editors.iter().any(|editor| {
 2002                                        let multi_buffer = editor.read(cx).buffer();
 2003                                        multi_buffer.read(cx).is_singleton()
 2004                                            && multi_buffer.read(cx).as_singleton().map_or(
 2005                                                false,
 2006                                                |singleton| {
 2007                                                    singleton.entity_id() == buffer.entity_id()
 2008                                                },
 2009                                            )
 2010                                    })
 2011                                })
 2012                            };
 2013                            if !edited_buffers_already_open {
 2014                                let workspace = workspace.downgrade();
 2015                                let transaction = transaction.clone();
 2016                                cx.defer_in(window, move |_, window, cx| {
 2017                                    cx.spawn_in(window, async move |editor, cx| {
 2018                                        Self::open_project_transaction(
 2019                                            &editor,
 2020                                            workspace,
 2021                                            transaction,
 2022                                            "Rename".to_string(),
 2023                                            cx,
 2024                                        )
 2025                                        .await
 2026                                        .ok()
 2027                                    })
 2028                                    .detach();
 2029                                });
 2030                            }
 2031                        }
 2032                    }
 2033
 2034                    _ => {}
 2035                },
 2036            ));
 2037            if let Some(task_inventory) = project
 2038                .read(cx)
 2039                .task_store()
 2040                .read(cx)
 2041                .task_inventory()
 2042                .cloned()
 2043            {
 2044                project_subscriptions.push(cx.observe_in(
 2045                    &task_inventory,
 2046                    window,
 2047                    |editor, _, window, cx| {
 2048                        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2049                    },
 2050                ));
 2051            };
 2052
 2053            project_subscriptions.push(cx.subscribe_in(
 2054                &project.read(cx).breakpoint_store(),
 2055                window,
 2056                |editor, _, event, window, cx| match event {
 2057                    BreakpointStoreEvent::ClearDebugLines => {
 2058                        editor.clear_row_highlights::<ActiveDebugLine>();
 2059                        editor.refresh_inline_values(cx);
 2060                    }
 2061                    BreakpointStoreEvent::SetDebugLine => {
 2062                        if editor.go_to_active_debug_line(window, cx) {
 2063                            cx.stop_propagation();
 2064                        }
 2065
 2066                        editor.refresh_inline_values(cx);
 2067                    }
 2068                    _ => {}
 2069                },
 2070            ));
 2071            let git_store = project.read(cx).git_store().clone();
 2072            let project = project.clone();
 2073            project_subscriptions.push(cx.subscribe(&git_store, move |this, _, event, cx| {
 2074                if let GitStoreEvent::RepositoryAdded = event {
 2075                    this.load_diff_task = Some(
 2076                        update_uncommitted_diff_for_buffer(
 2077                            cx.entity(),
 2078                            &project,
 2079                            this.buffer.read(cx).all_buffers(),
 2080                            this.buffer.clone(),
 2081                            cx,
 2082                        )
 2083                        .shared(),
 2084                    );
 2085                }
 2086            }));
 2087        }
 2088
 2089        let buffer_snapshot = multi_buffer.read(cx).snapshot(cx);
 2090
 2091        let inlay_hint_settings =
 2092            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 2093        let focus_handle = cx.focus_handle();
 2094        if !is_minimap {
 2095            cx.on_focus(&focus_handle, window, Self::handle_focus)
 2096                .detach();
 2097            cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 2098                .detach();
 2099            cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 2100                .detach();
 2101            cx.on_blur(&focus_handle, window, Self::handle_blur)
 2102                .detach();
 2103            cx.observe_pending_input(window, Self::observe_pending_input)
 2104                .detach();
 2105        }
 2106
 2107        let show_indent_guides =
 2108            if matches!(mode, EditorMode::SingleLine | EditorMode::Minimap { .. }) {
 2109                Some(false)
 2110            } else {
 2111                None
 2112            };
 2113
 2114        let breakpoint_store = match (&mode, project.as_ref()) {
 2115            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 2116            _ => None,
 2117        };
 2118
 2119        let mut code_action_providers = Vec::new();
 2120        let mut load_uncommitted_diff = None;
 2121        if let Some(project) = project.clone() {
 2122            load_uncommitted_diff = Some(
 2123                update_uncommitted_diff_for_buffer(
 2124                    cx.entity(),
 2125                    &project,
 2126                    multi_buffer.read(cx).all_buffers(),
 2127                    multi_buffer.clone(),
 2128                    cx,
 2129                )
 2130                .shared(),
 2131            );
 2132            code_action_providers.push(Rc::new(project) as Rc<_>);
 2133        }
 2134
 2135        let mut editor = Self {
 2136            focus_handle,
 2137            show_cursor_when_unfocused: false,
 2138            last_focused_descendant: None,
 2139            buffer: multi_buffer.clone(),
 2140            display_map: display_map.clone(),
 2141            placeholder_display_map: None,
 2142            selections,
 2143            scroll_manager: ScrollManager::new(cx),
 2144            columnar_selection_state: None,
 2145            add_selections_state: None,
 2146            select_next_state: None,
 2147            select_prev_state: None,
 2148            selection_history: SelectionHistory::default(),
 2149            defer_selection_effects: false,
 2150            deferred_selection_effects_state: None,
 2151            autoclose_regions: Vec::new(),
 2152            snippet_stack: InvalidationStack::default(),
 2153            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 2154            ime_transaction: None,
 2155            active_diagnostics: ActiveDiagnostic::None,
 2156            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 2157            inline_diagnostics_update: Task::ready(()),
 2158            inline_diagnostics: Vec::new(),
 2159            soft_wrap_mode_override,
 2160            diagnostics_max_severity,
 2161            hard_wrap: None,
 2162            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 2163            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 2164            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 2165            project,
 2166            blink_manager: blink_manager.clone(),
 2167            show_local_selections: true,
 2168            show_scrollbars: ScrollbarAxes {
 2169                horizontal: full_mode,
 2170                vertical: full_mode,
 2171            },
 2172            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 2173            offset_content: !matches!(mode, EditorMode::SingleLine),
 2174            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 2175            show_gutter: full_mode,
 2176            show_line_numbers: (!full_mode).then_some(false),
 2177            use_relative_line_numbers: None,
 2178            disable_expand_excerpt_buttons: !full_mode,
 2179            show_git_diff_gutter: None,
 2180            show_code_actions: None,
 2181            show_runnables: None,
 2182            show_breakpoints: None,
 2183            show_wrap_guides: None,
 2184            show_indent_guides,
 2185            highlight_order: 0,
 2186            highlighted_rows: HashMap::default(),
 2187            background_highlights: HashMap::default(),
 2188            gutter_highlights: HashMap::default(),
 2189            scrollbar_marker_state: ScrollbarMarkerState::default(),
 2190            active_indent_guides_state: ActiveIndentGuidesState::default(),
 2191            nav_history: None,
 2192            context_menu: RefCell::new(None),
 2193            context_menu_options: None,
 2194            mouse_context_menu: None,
 2195            completion_tasks: Vec::new(),
 2196            inline_blame_popover: None,
 2197            inline_blame_popover_show_task: None,
 2198            signature_help_state: SignatureHelpState::default(),
 2199            auto_signature_help: None,
 2200            find_all_references_task_sources: Vec::new(),
 2201            next_completion_id: 0,
 2202            next_inlay_id: 0,
 2203            code_action_providers,
 2204            available_code_actions: None,
 2205            code_actions_task: None,
 2206            quick_selection_highlight_task: None,
 2207            debounced_selection_highlight_task: None,
 2208            document_highlights_task: None,
 2209            linked_editing_range_task: None,
 2210            pending_rename: None,
 2211            searchable: !is_minimap,
 2212            cursor_shape: EditorSettings::get_global(cx)
 2213                .cursor_shape
 2214                .unwrap_or_default(),
 2215            current_line_highlight: None,
 2216            autoindent_mode: Some(AutoindentMode::EachLine),
 2217            collapse_matches: false,
 2218            workspace: None,
 2219            input_enabled: !is_minimap,
 2220            use_modal_editing: full_mode,
 2221            read_only: is_minimap,
 2222            use_autoclose: true,
 2223            use_auto_surround: true,
 2224            auto_replace_emoji_shortcode: false,
 2225            jsx_tag_auto_close_enabled_in_any_buffer: false,
 2226            leader_id: None,
 2227            remote_id: None,
 2228            hover_state: HoverState::default(),
 2229            pending_mouse_down: None,
 2230            hovered_link_state: None,
 2231            edit_prediction_provider: None,
 2232            active_edit_prediction: None,
 2233            stale_edit_prediction_in_menu: None,
 2234            edit_prediction_preview: EditPredictionPreview::Inactive {
 2235                released_too_fast: false,
 2236            },
 2237            inline_diagnostics_enabled: full_mode,
 2238            diagnostics_enabled: full_mode,
 2239            word_completions_enabled: full_mode,
 2240            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 2241            gutter_hovered: false,
 2242            pixel_position_of_newest_cursor: None,
 2243            last_bounds: None,
 2244            last_position_map: None,
 2245            expect_bounds_change: None,
 2246            gutter_dimensions: GutterDimensions::default(),
 2247            style: None,
 2248            show_cursor_names: false,
 2249            hovered_cursors: HashMap::default(),
 2250            next_editor_action_id: EditorActionId::default(),
 2251            editor_actions: Rc::default(),
 2252            edit_predictions_hidden_for_vim_mode: false,
 2253            show_edit_predictions_override: None,
 2254            menu_edit_predictions_policy: MenuEditPredictionsPolicy::ByProvider,
 2255            edit_prediction_settings: EditPredictionSettings::Disabled,
 2256            edit_prediction_indent_conflict: false,
 2257            edit_prediction_requires_modifier_in_indent_conflict: true,
 2258            custom_context_menu: None,
 2259            show_git_blame_gutter: false,
 2260            show_git_blame_inline: false,
 2261            show_selection_menu: None,
 2262            show_git_blame_inline_delay_task: None,
 2263            git_blame_inline_enabled: full_mode
 2264                && ProjectSettings::get_global(cx).git.inline_blame.enabled,
 2265            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 2266            buffer_serialization: is_minimap.not().then(|| {
 2267                BufferSerialization::new(
 2268                    ProjectSettings::get_global(cx)
 2269                        .session
 2270                        .restore_unsaved_buffers,
 2271                )
 2272            }),
 2273            blame: None,
 2274            blame_subscription: None,
 2275            tasks: BTreeMap::default(),
 2276
 2277            breakpoint_store,
 2278            gutter_breakpoint_indicator: (None, None),
 2279            hovered_diff_hunk_row: None,
 2280            _subscriptions: (!is_minimap)
 2281                .then(|| {
 2282                    vec![
 2283                        cx.observe(&multi_buffer, Self::on_buffer_changed),
 2284                        cx.subscribe_in(&multi_buffer, window, Self::on_buffer_event),
 2285                        cx.observe_in(&display_map, window, Self::on_display_map_changed),
 2286                        cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 2287                        cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 2288                        observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 2289                        cx.observe_window_activation(window, |editor, window, cx| {
 2290                            let active = window.is_window_active();
 2291                            editor.blink_manager.update(cx, |blink_manager, cx| {
 2292                                if active {
 2293                                    blink_manager.enable(cx);
 2294                                } else {
 2295                                    blink_manager.disable(cx);
 2296                                }
 2297                            });
 2298                            if active {
 2299                                editor.show_mouse_cursor(cx);
 2300                            }
 2301                        }),
 2302                    ]
 2303                })
 2304                .unwrap_or_default(),
 2305            tasks_update_task: None,
 2306            pull_diagnostics_task: Task::ready(()),
 2307            colors: None,
 2308            refresh_colors_task: Task::ready(()),
 2309            inlay_hints: None,
 2310            next_color_inlay_id: 0,
 2311            post_scroll_update: Task::ready(()),
 2312            linked_edit_ranges: Default::default(),
 2313            in_project_search: false,
 2314            previous_search_ranges: None,
 2315            breadcrumb_header: None,
 2316            focused_block: None,
 2317            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 2318            addons: HashMap::default(),
 2319            registered_buffers: HashMap::default(),
 2320            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 2321            selection_mark_mode: false,
 2322            toggle_fold_multiple_buffers: Task::ready(()),
 2323            serialize_selections: Task::ready(()),
 2324            serialize_folds: Task::ready(()),
 2325            text_style_refinement: None,
 2326            load_diff_task: load_uncommitted_diff,
 2327            temporary_diff_override: false,
 2328            mouse_cursor_hidden: false,
 2329            minimap: None,
 2330            hide_mouse_mode: EditorSettings::get_global(cx)
 2331                .hide_mouse
 2332                .unwrap_or_default(),
 2333            change_list: ChangeList::new(),
 2334            mode,
 2335            selection_drag_state: SelectionDragState::None,
 2336            folding_newlines: Task::ready(()),
 2337            lookup_key: None,
 2338            select_next_is_case_sensitive: None,
 2339        };
 2340
 2341        if is_minimap {
 2342            return editor;
 2343        }
 2344
 2345        if let Some(breakpoints) = editor.breakpoint_store.as_ref() {
 2346            editor
 2347                ._subscriptions
 2348                .push(cx.observe(breakpoints, |_, _, cx| {
 2349                    cx.notify();
 2350                }));
 2351        }
 2352        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2353        editor._subscriptions.extend(project_subscriptions);
 2354
 2355        editor._subscriptions.push(cx.subscribe_in(
 2356            &cx.entity(),
 2357            window,
 2358            |editor, _, e: &EditorEvent, window, cx| match e {
 2359                EditorEvent::ScrollPositionChanged { local, .. } => {
 2360                    if *local {
 2361                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 2362                        editor.inline_blame_popover.take();
 2363                        let new_anchor = editor.scroll_manager.anchor();
 2364                        let snapshot = editor.snapshot(window, cx);
 2365                        editor.update_restoration_data(cx, move |data| {
 2366                            data.scroll_position = (
 2367                                new_anchor.top_row(snapshot.buffer_snapshot()),
 2368                                new_anchor.offset,
 2369                            );
 2370                        });
 2371
 2372                        editor.post_scroll_update = cx.spawn_in(window, async move |editor, cx| {
 2373                            cx.background_executor()
 2374                                .timer(Duration::from_millis(50))
 2375                                .await;
 2376                            editor
 2377                                .update_in(cx, |editor, window, cx| {
 2378                                    editor.register_visible_buffers(cx);
 2379                                    editor.refresh_colors_for_visible_range(None, window, cx);
 2380                                    editor.refresh_inlay_hints(
 2381                                        InlayHintRefreshReason::NewLinesShown,
 2382                                        cx,
 2383                                    );
 2384                                })
 2385                                .ok();
 2386                        });
 2387                    }
 2388                }
 2389                EditorEvent::Edited { .. } => {
 2390                    let vim_mode = vim_mode_setting::VimModeSetting::try_get(cx)
 2391                        .map(|vim_mode| vim_mode.0)
 2392                        .unwrap_or(false);
 2393                    if !vim_mode {
 2394                        let display_map = editor.display_snapshot(cx);
 2395                        let selections = editor.selections.all_adjusted_display(&display_map);
 2396                        let pop_state = editor
 2397                            .change_list
 2398                            .last()
 2399                            .map(|previous| {
 2400                                previous.len() == selections.len()
 2401                                    && previous.iter().enumerate().all(|(ix, p)| {
 2402                                        p.to_display_point(&display_map).row()
 2403                                            == selections[ix].head().row()
 2404                                    })
 2405                            })
 2406                            .unwrap_or(false);
 2407                        let new_positions = selections
 2408                            .into_iter()
 2409                            .map(|s| display_map.display_point_to_anchor(s.head(), Bias::Left))
 2410                            .collect();
 2411                        editor
 2412                            .change_list
 2413                            .push_to_change_list(pop_state, new_positions);
 2414                    }
 2415                }
 2416                _ => (),
 2417            },
 2418        ));
 2419
 2420        if let Some(dap_store) = editor
 2421            .project
 2422            .as_ref()
 2423            .map(|project| project.read(cx).dap_store())
 2424        {
 2425            let weak_editor = cx.weak_entity();
 2426
 2427            editor
 2428                ._subscriptions
 2429                .push(
 2430                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2431                        let session_entity = cx.entity();
 2432                        weak_editor
 2433                            .update(cx, |editor, cx| {
 2434                                editor._subscriptions.push(
 2435                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2436                                );
 2437                            })
 2438                            .ok();
 2439                    }),
 2440                );
 2441
 2442            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2443                editor
 2444                    ._subscriptions
 2445                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2446            }
 2447        }
 2448
 2449        // skip adding the initial selection to selection history
 2450        editor.selection_history.mode = SelectionHistoryMode::Skipping;
 2451        editor.end_selection(window, cx);
 2452        editor.selection_history.mode = SelectionHistoryMode::Normal;
 2453
 2454        editor.scroll_manager.show_scrollbars(window, cx);
 2455        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut editor, &multi_buffer, cx);
 2456
 2457        if full_mode {
 2458            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2459            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2460
 2461            if editor.git_blame_inline_enabled {
 2462                editor.start_git_blame_inline(false, window, cx);
 2463            }
 2464
 2465            editor.go_to_active_debug_line(window, cx);
 2466
 2467            editor.minimap =
 2468                editor.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2469            editor.colors = Some(LspColorData::new(cx));
 2470            editor.inlay_hints = Some(LspInlayHintData::new(inlay_hint_settings));
 2471
 2472            if let Some(buffer) = multi_buffer.read(cx).as_singleton() {
 2473                editor.register_buffer(buffer.read(cx).remote_id(), cx);
 2474            }
 2475            editor.update_lsp_data(None, window, cx);
 2476            editor.report_editor_event(ReportEditorEvent::EditorOpened, None, cx);
 2477        }
 2478
 2479        editor
 2480    }
 2481
 2482    pub fn display_snapshot(&self, cx: &mut App) -> DisplaySnapshot {
 2483        self.display_map.update(cx, |map, cx| map.snapshot(cx))
 2484    }
 2485
 2486    pub fn deploy_mouse_context_menu(
 2487        &mut self,
 2488        position: gpui::Point<Pixels>,
 2489        context_menu: Entity<ContextMenu>,
 2490        window: &mut Window,
 2491        cx: &mut Context<Self>,
 2492    ) {
 2493        self.mouse_context_menu = Some(MouseContextMenu::new(
 2494            self,
 2495            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2496            context_menu,
 2497            window,
 2498            cx,
 2499        ));
 2500    }
 2501
 2502    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2503        self.mouse_context_menu
 2504            .as_ref()
 2505            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2506    }
 2507
 2508    pub fn is_range_selected(&mut self, range: &Range<Anchor>, cx: &mut Context<Self>) -> bool {
 2509        if self
 2510            .selections
 2511            .pending_anchor()
 2512            .is_some_and(|pending_selection| {
 2513                let snapshot = self.buffer().read(cx).snapshot(cx);
 2514                pending_selection.range().includes(range, &snapshot)
 2515            })
 2516        {
 2517            return true;
 2518        }
 2519
 2520        self.selections
 2521            .disjoint_in_range::<usize>(range.clone(), &self.display_snapshot(cx))
 2522            .into_iter()
 2523            .any(|selection| {
 2524                // This is needed to cover a corner case, if we just check for an existing
 2525                // selection in the fold range, having a cursor at the start of the fold
 2526                // marks it as selected. Non-empty selections don't cause this.
 2527                let length = selection.end - selection.start;
 2528                length > 0
 2529            })
 2530    }
 2531
 2532    pub fn key_context(&self, window: &mut Window, cx: &mut App) -> KeyContext {
 2533        self.key_context_internal(self.has_active_edit_prediction(), window, cx)
 2534    }
 2535
 2536    fn key_context_internal(
 2537        &self,
 2538        has_active_edit_prediction: bool,
 2539        window: &mut Window,
 2540        cx: &mut App,
 2541    ) -> KeyContext {
 2542        let mut key_context = KeyContext::new_with_defaults();
 2543        key_context.add("Editor");
 2544        let mode = match self.mode {
 2545            EditorMode::SingleLine => "single_line",
 2546            EditorMode::AutoHeight { .. } => "auto_height",
 2547            EditorMode::Minimap { .. } => "minimap",
 2548            EditorMode::Full { .. } => "full",
 2549        };
 2550
 2551        if EditorSettings::jupyter_enabled(cx) {
 2552            key_context.add("jupyter");
 2553        }
 2554
 2555        key_context.set("mode", mode);
 2556        if self.pending_rename.is_some() {
 2557            key_context.add("renaming");
 2558        }
 2559
 2560        if let Some(snippet_stack) = self.snippet_stack.last() {
 2561            key_context.add("in_snippet");
 2562
 2563            if snippet_stack.active_index > 0 {
 2564                key_context.add("has_previous_tabstop");
 2565            }
 2566
 2567            if snippet_stack.active_index < snippet_stack.ranges.len().saturating_sub(1) {
 2568                key_context.add("has_next_tabstop");
 2569            }
 2570        }
 2571
 2572        match self.context_menu.borrow().as_ref() {
 2573            Some(CodeContextMenu::Completions(menu)) => {
 2574                if menu.visible() {
 2575                    key_context.add("menu");
 2576                    key_context.add("showing_completions");
 2577                }
 2578            }
 2579            Some(CodeContextMenu::CodeActions(menu)) => {
 2580                if menu.visible() {
 2581                    key_context.add("menu");
 2582                    key_context.add("showing_code_actions")
 2583                }
 2584            }
 2585            None => {}
 2586        }
 2587
 2588        if self.signature_help_state.has_multiple_signatures() {
 2589            key_context.add("showing_signature_help");
 2590        }
 2591
 2592        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2593        if !self.focus_handle(cx).contains_focused(window, cx)
 2594            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2595        {
 2596            for addon in self.addons.values() {
 2597                addon.extend_key_context(&mut key_context, cx)
 2598            }
 2599        }
 2600
 2601        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2602            if let Some(extension) = singleton_buffer.read(cx).file().and_then(|file| {
 2603                Some(
 2604                    file.full_path(cx)
 2605                        .extension()?
 2606                        .to_string_lossy()
 2607                        .into_owned(),
 2608                )
 2609            }) {
 2610                key_context.set("extension", extension);
 2611            }
 2612        } else {
 2613            key_context.add("multibuffer");
 2614        }
 2615
 2616        if has_active_edit_prediction {
 2617            if self.edit_prediction_in_conflict() {
 2618                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2619            } else {
 2620                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2621                key_context.add("copilot_suggestion");
 2622            }
 2623        }
 2624
 2625        if self.selection_mark_mode {
 2626            key_context.add("selection_mode");
 2627        }
 2628
 2629        let disjoint = self.selections.disjoint_anchors();
 2630        let snapshot = self.snapshot(window, cx);
 2631        let snapshot = snapshot.buffer_snapshot();
 2632        if self.mode == EditorMode::SingleLine
 2633            && let [selection] = disjoint
 2634            && selection.start == selection.end
 2635            && selection.end.to_offset(snapshot) == snapshot.len()
 2636        {
 2637            key_context.add("end_of_input");
 2638        }
 2639
 2640        key_context
 2641    }
 2642
 2643    pub fn last_bounds(&self) -> Option<&Bounds<Pixels>> {
 2644        self.last_bounds.as_ref()
 2645    }
 2646
 2647    fn show_mouse_cursor(&mut self, cx: &mut Context<Self>) {
 2648        if self.mouse_cursor_hidden {
 2649            self.mouse_cursor_hidden = false;
 2650            cx.notify();
 2651        }
 2652    }
 2653
 2654    pub fn hide_mouse_cursor(&mut self, origin: HideMouseCursorOrigin, cx: &mut Context<Self>) {
 2655        let hide_mouse_cursor = match origin {
 2656            HideMouseCursorOrigin::TypingAction => {
 2657                matches!(
 2658                    self.hide_mouse_mode,
 2659                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2660                )
 2661            }
 2662            HideMouseCursorOrigin::MovementAction => {
 2663                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2664            }
 2665        };
 2666        if self.mouse_cursor_hidden != hide_mouse_cursor {
 2667            self.mouse_cursor_hidden = hide_mouse_cursor;
 2668            cx.notify();
 2669        }
 2670    }
 2671
 2672    pub fn edit_prediction_in_conflict(&self) -> bool {
 2673        if !self.show_edit_predictions_in_menu() {
 2674            return false;
 2675        }
 2676
 2677        let showing_completions = self
 2678            .context_menu
 2679            .borrow()
 2680            .as_ref()
 2681            .is_some_and(|context| matches!(context, CodeContextMenu::Completions(_)));
 2682
 2683        showing_completions
 2684            || self.edit_prediction_requires_modifier()
 2685            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2686            // bindings to insert tab characters.
 2687            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2688    }
 2689
 2690    pub fn accept_edit_prediction_keybind(
 2691        &self,
 2692        accept_partial: bool,
 2693        window: &mut Window,
 2694        cx: &mut App,
 2695    ) -> AcceptEditPredictionBinding {
 2696        let key_context = self.key_context_internal(true, window, cx);
 2697        let in_conflict = self.edit_prediction_in_conflict();
 2698
 2699        let bindings = if accept_partial {
 2700            window.bindings_for_action_in_context(&AcceptPartialEditPrediction, key_context)
 2701        } else {
 2702            window.bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2703        };
 2704
 2705        // TODO: if the binding contains multiple keystrokes, display all of them, not
 2706        // just the first one.
 2707        AcceptEditPredictionBinding(bindings.into_iter().rev().find(|binding| {
 2708            !in_conflict
 2709                || binding
 2710                    .keystrokes()
 2711                    .first()
 2712                    .is_some_and(|keystroke| keystroke.modifiers().modified())
 2713        }))
 2714    }
 2715
 2716    pub fn new_file(
 2717        workspace: &mut Workspace,
 2718        _: &workspace::NewFile,
 2719        window: &mut Window,
 2720        cx: &mut Context<Workspace>,
 2721    ) {
 2722        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2723            "Failed to create buffer",
 2724            window,
 2725            cx,
 2726            |e, _, _| match e.error_code() {
 2727                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2728                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2729                e.error_tag("required").unwrap_or("the latest version")
 2730            )),
 2731                _ => None,
 2732            },
 2733        );
 2734    }
 2735
 2736    pub fn new_in_workspace(
 2737        workspace: &mut Workspace,
 2738        window: &mut Window,
 2739        cx: &mut Context<Workspace>,
 2740    ) -> Task<Result<Entity<Editor>>> {
 2741        let project = workspace.project().clone();
 2742        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2743
 2744        cx.spawn_in(window, async move |workspace, cx| {
 2745            let buffer = create.await?;
 2746            workspace.update_in(cx, |workspace, window, cx| {
 2747                let editor =
 2748                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2749                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2750                editor
 2751            })
 2752        })
 2753    }
 2754
 2755    fn new_file_vertical(
 2756        workspace: &mut Workspace,
 2757        _: &workspace::NewFileSplitVertical,
 2758        window: &mut Window,
 2759        cx: &mut Context<Workspace>,
 2760    ) {
 2761        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2762    }
 2763
 2764    fn new_file_horizontal(
 2765        workspace: &mut Workspace,
 2766        _: &workspace::NewFileSplitHorizontal,
 2767        window: &mut Window,
 2768        cx: &mut Context<Workspace>,
 2769    ) {
 2770        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2771    }
 2772
 2773    fn new_file_split(
 2774        workspace: &mut Workspace,
 2775        action: &workspace::NewFileSplit,
 2776        window: &mut Window,
 2777        cx: &mut Context<Workspace>,
 2778    ) {
 2779        Self::new_file_in_direction(workspace, action.0, window, cx)
 2780    }
 2781
 2782    fn new_file_in_direction(
 2783        workspace: &mut Workspace,
 2784        direction: SplitDirection,
 2785        window: &mut Window,
 2786        cx: &mut Context<Workspace>,
 2787    ) {
 2788        let project = workspace.project().clone();
 2789        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2790
 2791        cx.spawn_in(window, async move |workspace, cx| {
 2792            let buffer = create.await?;
 2793            workspace.update_in(cx, move |workspace, window, cx| {
 2794                workspace.split_item(
 2795                    direction,
 2796                    Box::new(
 2797                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2798                    ),
 2799                    window,
 2800                    cx,
 2801                )
 2802            })?;
 2803            anyhow::Ok(())
 2804        })
 2805        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2806            match e.error_code() {
 2807                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2808                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2809                e.error_tag("required").unwrap_or("the latest version")
 2810            )),
 2811                _ => None,
 2812            }
 2813        });
 2814    }
 2815
 2816    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2817        self.leader_id
 2818    }
 2819
 2820    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2821        &self.buffer
 2822    }
 2823
 2824    pub fn project(&self) -> Option<&Entity<Project>> {
 2825        self.project.as_ref()
 2826    }
 2827
 2828    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2829        self.workspace.as_ref()?.0.upgrade()
 2830    }
 2831
 2832    /// Returns the workspace serialization ID if this editor should be serialized.
 2833    fn workspace_serialization_id(&self, _cx: &App) -> Option<WorkspaceId> {
 2834        self.workspace
 2835            .as_ref()
 2836            .filter(|_| self.should_serialize_buffer())
 2837            .and_then(|workspace| workspace.1)
 2838    }
 2839
 2840    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2841        self.buffer().read(cx).title(cx)
 2842    }
 2843
 2844    pub fn snapshot(&self, window: &Window, cx: &mut App) -> EditorSnapshot {
 2845        let git_blame_gutter_max_author_length = self
 2846            .render_git_blame_gutter(cx)
 2847            .then(|| {
 2848                if let Some(blame) = self.blame.as_ref() {
 2849                    let max_author_length =
 2850                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2851                    Some(max_author_length)
 2852                } else {
 2853                    None
 2854                }
 2855            })
 2856            .flatten();
 2857
 2858        EditorSnapshot {
 2859            mode: self.mode.clone(),
 2860            show_gutter: self.show_gutter,
 2861            show_line_numbers: self.show_line_numbers,
 2862            show_git_diff_gutter: self.show_git_diff_gutter,
 2863            show_code_actions: self.show_code_actions,
 2864            show_runnables: self.show_runnables,
 2865            show_breakpoints: self.show_breakpoints,
 2866            git_blame_gutter_max_author_length,
 2867            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2868            placeholder_display_snapshot: self
 2869                .placeholder_display_map
 2870                .as_ref()
 2871                .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx))),
 2872            scroll_anchor: self.scroll_manager.anchor(),
 2873            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2874            is_focused: self.focus_handle.is_focused(window),
 2875            current_line_highlight: self
 2876                .current_line_highlight
 2877                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2878            gutter_hovered: self.gutter_hovered,
 2879        }
 2880    }
 2881
 2882    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2883        self.buffer.read(cx).language_at(point, cx)
 2884    }
 2885
 2886    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2887        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2888    }
 2889
 2890    pub fn active_excerpt(
 2891        &self,
 2892        cx: &App,
 2893    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2894        self.buffer
 2895            .read(cx)
 2896            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2897    }
 2898
 2899    pub fn mode(&self) -> &EditorMode {
 2900        &self.mode
 2901    }
 2902
 2903    pub fn set_mode(&mut self, mode: EditorMode) {
 2904        self.mode = mode;
 2905    }
 2906
 2907    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2908        self.collaboration_hub.as_deref()
 2909    }
 2910
 2911    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2912        self.collaboration_hub = Some(hub);
 2913    }
 2914
 2915    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2916        self.in_project_search = in_project_search;
 2917    }
 2918
 2919    pub fn set_custom_context_menu(
 2920        &mut self,
 2921        f: impl 'static
 2922        + Fn(
 2923            &mut Self,
 2924            DisplayPoint,
 2925            &mut Window,
 2926            &mut Context<Self>,
 2927        ) -> Option<Entity<ui::ContextMenu>>,
 2928    ) {
 2929        self.custom_context_menu = Some(Box::new(f))
 2930    }
 2931
 2932    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 2933        self.completion_provider = provider;
 2934    }
 2935
 2936    #[cfg(any(test, feature = "test-support"))]
 2937    pub fn completion_provider(&self) -> Option<Rc<dyn CompletionProvider>> {
 2938        self.completion_provider.clone()
 2939    }
 2940
 2941    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 2942        self.semantics_provider.clone()
 2943    }
 2944
 2945    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 2946        self.semantics_provider = provider;
 2947    }
 2948
 2949    pub fn set_edit_prediction_provider<T>(
 2950        &mut self,
 2951        provider: Option<Entity<T>>,
 2952        window: &mut Window,
 2953        cx: &mut Context<Self>,
 2954    ) where
 2955        T: EditPredictionProvider,
 2956    {
 2957        self.edit_prediction_provider = provider.map(|provider| RegisteredEditPredictionProvider {
 2958            _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 2959                if this.focus_handle.is_focused(window) {
 2960                    this.update_visible_edit_prediction(window, cx);
 2961                }
 2962            }),
 2963            provider: Arc::new(provider),
 2964        });
 2965        self.update_edit_prediction_settings(cx);
 2966        self.refresh_edit_prediction(false, false, window, cx);
 2967    }
 2968
 2969    pub fn placeholder_text(&self, cx: &mut App) -> Option<String> {
 2970        self.placeholder_display_map
 2971            .as_ref()
 2972            .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx)).text())
 2973    }
 2974
 2975    pub fn set_placeholder_text(
 2976        &mut self,
 2977        placeholder_text: &str,
 2978        window: &mut Window,
 2979        cx: &mut Context<Self>,
 2980    ) {
 2981        let multibuffer = cx
 2982            .new(|cx| MultiBuffer::singleton(cx.new(|cx| Buffer::local(placeholder_text, cx)), cx));
 2983
 2984        let style = window.text_style();
 2985
 2986        self.placeholder_display_map = Some(cx.new(|cx| {
 2987            DisplayMap::new(
 2988                multibuffer,
 2989                style.font(),
 2990                style.font_size.to_pixels(window.rem_size()),
 2991                None,
 2992                FILE_HEADER_HEIGHT,
 2993                MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 2994                Default::default(),
 2995                DiagnosticSeverity::Off,
 2996                cx,
 2997            )
 2998        }));
 2999        cx.notify();
 3000    }
 3001
 3002    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 3003        self.cursor_shape = cursor_shape;
 3004
 3005        // Disrupt blink for immediate user feedback that the cursor shape has changed
 3006        self.blink_manager.update(cx, BlinkManager::show_cursor);
 3007
 3008        cx.notify();
 3009    }
 3010
 3011    pub fn set_current_line_highlight(
 3012        &mut self,
 3013        current_line_highlight: Option<CurrentLineHighlight>,
 3014    ) {
 3015        self.current_line_highlight = current_line_highlight;
 3016    }
 3017
 3018    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 3019        self.collapse_matches = collapse_matches;
 3020    }
 3021
 3022    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 3023        if self.collapse_matches {
 3024            return range.start..range.start;
 3025        }
 3026        range.clone()
 3027    }
 3028
 3029    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 3030        if self.display_map.read(cx).clip_at_line_ends != clip {
 3031            self.display_map
 3032                .update(cx, |map, _| map.clip_at_line_ends = clip);
 3033        }
 3034    }
 3035
 3036    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 3037        self.input_enabled = input_enabled;
 3038    }
 3039
 3040    pub fn set_edit_predictions_hidden_for_vim_mode(
 3041        &mut self,
 3042        hidden: bool,
 3043        window: &mut Window,
 3044        cx: &mut Context<Self>,
 3045    ) {
 3046        if hidden != self.edit_predictions_hidden_for_vim_mode {
 3047            self.edit_predictions_hidden_for_vim_mode = hidden;
 3048            if hidden {
 3049                self.update_visible_edit_prediction(window, cx);
 3050            } else {
 3051                self.refresh_edit_prediction(true, false, window, cx);
 3052            }
 3053        }
 3054    }
 3055
 3056    pub fn set_menu_edit_predictions_policy(&mut self, value: MenuEditPredictionsPolicy) {
 3057        self.menu_edit_predictions_policy = value;
 3058    }
 3059
 3060    pub fn set_autoindent(&mut self, autoindent: bool) {
 3061        if autoindent {
 3062            self.autoindent_mode = Some(AutoindentMode::EachLine);
 3063        } else {
 3064            self.autoindent_mode = None;
 3065        }
 3066    }
 3067
 3068    pub fn read_only(&self, cx: &App) -> bool {
 3069        self.read_only || self.buffer.read(cx).read_only()
 3070    }
 3071
 3072    pub fn set_read_only(&mut self, read_only: bool) {
 3073        self.read_only = read_only;
 3074    }
 3075
 3076    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 3077        self.use_autoclose = autoclose;
 3078    }
 3079
 3080    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 3081        self.use_auto_surround = auto_surround;
 3082    }
 3083
 3084    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 3085        self.auto_replace_emoji_shortcode = auto_replace;
 3086    }
 3087
 3088    pub fn set_should_serialize(&mut self, should_serialize: bool, cx: &App) {
 3089        self.buffer_serialization = should_serialize.then(|| {
 3090            BufferSerialization::new(
 3091                ProjectSettings::get_global(cx)
 3092                    .session
 3093                    .restore_unsaved_buffers,
 3094            )
 3095        })
 3096    }
 3097
 3098    fn should_serialize_buffer(&self) -> bool {
 3099        self.buffer_serialization.is_some()
 3100    }
 3101
 3102    pub fn toggle_edit_predictions(
 3103        &mut self,
 3104        _: &ToggleEditPrediction,
 3105        window: &mut Window,
 3106        cx: &mut Context<Self>,
 3107    ) {
 3108        if self.show_edit_predictions_override.is_some() {
 3109            self.set_show_edit_predictions(None, window, cx);
 3110        } else {
 3111            let show_edit_predictions = !self.edit_predictions_enabled();
 3112            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 3113        }
 3114    }
 3115
 3116    pub fn set_show_edit_predictions(
 3117        &mut self,
 3118        show_edit_predictions: Option<bool>,
 3119        window: &mut Window,
 3120        cx: &mut Context<Self>,
 3121    ) {
 3122        self.show_edit_predictions_override = show_edit_predictions;
 3123        self.update_edit_prediction_settings(cx);
 3124
 3125        if let Some(false) = show_edit_predictions {
 3126            self.discard_edit_prediction(false, cx);
 3127        } else {
 3128            self.refresh_edit_prediction(false, true, window, cx);
 3129        }
 3130    }
 3131
 3132    fn edit_predictions_disabled_in_scope(
 3133        &self,
 3134        buffer: &Entity<Buffer>,
 3135        buffer_position: language::Anchor,
 3136        cx: &App,
 3137    ) -> bool {
 3138        let snapshot = buffer.read(cx).snapshot();
 3139        let settings = snapshot.settings_at(buffer_position, cx);
 3140
 3141        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 3142            return false;
 3143        };
 3144
 3145        scope.override_name().is_some_and(|scope_name| {
 3146            settings
 3147                .edit_predictions_disabled_in
 3148                .iter()
 3149                .any(|s| s == scope_name)
 3150        })
 3151    }
 3152
 3153    pub fn set_use_modal_editing(&mut self, to: bool) {
 3154        self.use_modal_editing = to;
 3155    }
 3156
 3157    pub fn use_modal_editing(&self) -> bool {
 3158        self.use_modal_editing
 3159    }
 3160
 3161    fn selections_did_change(
 3162        &mut self,
 3163        local: bool,
 3164        old_cursor_position: &Anchor,
 3165        effects: SelectionEffects,
 3166        window: &mut Window,
 3167        cx: &mut Context<Self>,
 3168    ) {
 3169        window.invalidate_character_coordinates();
 3170
 3171        // Copy selections to primary selection buffer
 3172        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 3173        if local {
 3174            let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
 3175            let buffer_handle = self.buffer.read(cx).read(cx);
 3176
 3177            let mut text = String::new();
 3178            for (index, selection) in selections.iter().enumerate() {
 3179                let text_for_selection = buffer_handle
 3180                    .text_for_range(selection.start..selection.end)
 3181                    .collect::<String>();
 3182
 3183                text.push_str(&text_for_selection);
 3184                if index != selections.len() - 1 {
 3185                    text.push('\n');
 3186                }
 3187            }
 3188
 3189            if !text.is_empty() {
 3190                cx.write_to_primary(ClipboardItem::new_string(text));
 3191            }
 3192        }
 3193
 3194        let selection_anchors = self.selections.disjoint_anchors_arc();
 3195
 3196        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 3197            self.buffer.update(cx, |buffer, cx| {
 3198                buffer.set_active_selections(
 3199                    &selection_anchors,
 3200                    self.selections.line_mode(),
 3201                    self.cursor_shape,
 3202                    cx,
 3203                )
 3204            });
 3205        }
 3206        let display_map = self
 3207            .display_map
 3208            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3209        let buffer = display_map.buffer_snapshot();
 3210        if self.selections.count() == 1 {
 3211            self.add_selections_state = None;
 3212        }
 3213        self.select_next_state = None;
 3214        self.select_prev_state = None;
 3215        self.select_syntax_node_history.try_clear();
 3216        self.invalidate_autoclose_regions(&selection_anchors, buffer);
 3217        self.snippet_stack.invalidate(&selection_anchors, buffer);
 3218        self.take_rename(false, window, cx);
 3219
 3220        let newest_selection = self.selections.newest_anchor();
 3221        let new_cursor_position = newest_selection.head();
 3222        let selection_start = newest_selection.start;
 3223
 3224        if effects.nav_history.is_none() || effects.nav_history == Some(true) {
 3225            self.push_to_nav_history(
 3226                *old_cursor_position,
 3227                Some(new_cursor_position.to_point(buffer)),
 3228                false,
 3229                effects.nav_history == Some(true),
 3230                cx,
 3231            );
 3232        }
 3233
 3234        if local {
 3235            if let Some(buffer_id) = new_cursor_position.buffer_id {
 3236                self.register_buffer(buffer_id, cx);
 3237            }
 3238
 3239            let mut context_menu = self.context_menu.borrow_mut();
 3240            let completion_menu = match context_menu.as_ref() {
 3241                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 3242                Some(CodeContextMenu::CodeActions(_)) => {
 3243                    *context_menu = None;
 3244                    None
 3245                }
 3246                None => None,
 3247            };
 3248            let completion_position = completion_menu.map(|menu| menu.initial_position);
 3249            drop(context_menu);
 3250
 3251            if effects.completions
 3252                && let Some(completion_position) = completion_position
 3253            {
 3254                let start_offset = selection_start.to_offset(buffer);
 3255                let position_matches = start_offset == completion_position.to_offset(buffer);
 3256                let continue_showing = if position_matches {
 3257                    if self.snippet_stack.is_empty() {
 3258                        buffer.char_kind_before(start_offset, Some(CharScopeContext::Completion))
 3259                            == Some(CharKind::Word)
 3260                    } else {
 3261                        // Snippet choices can be shown even when the cursor is in whitespace.
 3262                        // Dismissing the menu with actions like backspace is handled by
 3263                        // invalidation regions.
 3264                        true
 3265                    }
 3266                } else {
 3267                    false
 3268                };
 3269
 3270                if continue_showing {
 3271                    self.open_or_update_completions_menu(None, None, false, window, cx);
 3272                } else {
 3273                    self.hide_context_menu(window, cx);
 3274                }
 3275            }
 3276
 3277            hide_hover(self, cx);
 3278
 3279            if old_cursor_position.to_display_point(&display_map).row()
 3280                != new_cursor_position.to_display_point(&display_map).row()
 3281            {
 3282                self.available_code_actions.take();
 3283            }
 3284            self.refresh_code_actions(window, cx);
 3285            self.refresh_document_highlights(cx);
 3286            refresh_linked_ranges(self, window, cx);
 3287
 3288            self.refresh_selected_text_highlights(false, window, cx);
 3289            self.refresh_matching_bracket_highlights(window, cx);
 3290            self.update_visible_edit_prediction(window, cx);
 3291            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 3292            self.inline_blame_popover.take();
 3293            if self.git_blame_inline_enabled {
 3294                self.start_inline_blame_timer(window, cx);
 3295            }
 3296        }
 3297
 3298        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 3299        cx.emit(EditorEvent::SelectionsChanged { local });
 3300
 3301        let selections = &self.selections.disjoint_anchors_arc();
 3302        if selections.len() == 1 {
 3303            cx.emit(SearchEvent::ActiveMatchChanged)
 3304        }
 3305        if local && let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 3306            let inmemory_selections = selections
 3307                .iter()
 3308                .map(|s| {
 3309                    text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 3310                        ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 3311                })
 3312                .collect();
 3313            self.update_restoration_data(cx, |data| {
 3314                data.selections = inmemory_selections;
 3315            });
 3316
 3317            if WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
 3318                && let Some(workspace_id) = self.workspace_serialization_id(cx)
 3319            {
 3320                let snapshot = self.buffer().read(cx).snapshot(cx);
 3321                let selections = selections.clone();
 3322                let background_executor = cx.background_executor().clone();
 3323                let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3324                self.serialize_selections = cx.background_spawn(async move {
 3325                    background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3326                    let db_selections = selections
 3327                        .iter()
 3328                        .map(|selection| {
 3329                            (
 3330                                selection.start.to_offset(&snapshot),
 3331                                selection.end.to_offset(&snapshot),
 3332                            )
 3333                        })
 3334                        .collect();
 3335
 3336                    DB.save_editor_selections(editor_id, workspace_id, db_selections)
 3337                        .await
 3338                        .with_context(|| {
 3339                            format!(
 3340                                "persisting editor selections for editor {editor_id}, \
 3341                                workspace {workspace_id:?}"
 3342                            )
 3343                        })
 3344                        .log_err();
 3345                });
 3346            }
 3347        }
 3348
 3349        cx.notify();
 3350    }
 3351
 3352    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 3353        use text::ToOffset as _;
 3354        use text::ToPoint as _;
 3355
 3356        if self.mode.is_minimap()
 3357            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 3358        {
 3359            return;
 3360        }
 3361
 3362        if !self.buffer().read(cx).is_singleton() {
 3363            return;
 3364        }
 3365
 3366        let display_snapshot = self
 3367            .display_map
 3368            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3369        let Some((.., snapshot)) = display_snapshot.buffer_snapshot().as_singleton() else {
 3370            return;
 3371        };
 3372        let inmemory_folds = display_snapshot
 3373            .folds_in_range(0..display_snapshot.buffer_snapshot().len())
 3374            .map(|fold| {
 3375                fold.range.start.text_anchor.to_point(&snapshot)
 3376                    ..fold.range.end.text_anchor.to_point(&snapshot)
 3377            })
 3378            .collect();
 3379        self.update_restoration_data(cx, |data| {
 3380            data.folds = inmemory_folds;
 3381        });
 3382
 3383        let Some(workspace_id) = self.workspace_serialization_id(cx) else {
 3384            return;
 3385        };
 3386        let background_executor = cx.background_executor().clone();
 3387        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3388        let db_folds = display_snapshot
 3389            .folds_in_range(0..display_snapshot.buffer_snapshot().len())
 3390            .map(|fold| {
 3391                (
 3392                    fold.range.start.text_anchor.to_offset(&snapshot),
 3393                    fold.range.end.text_anchor.to_offset(&snapshot),
 3394                )
 3395            })
 3396            .collect();
 3397        self.serialize_folds = cx.background_spawn(async move {
 3398            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3399            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 3400                .await
 3401                .with_context(|| {
 3402                    format!(
 3403                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 3404                    )
 3405                })
 3406                .log_err();
 3407        });
 3408    }
 3409
 3410    pub fn sync_selections(
 3411        &mut self,
 3412        other: Entity<Editor>,
 3413        cx: &mut Context<Self>,
 3414    ) -> gpui::Subscription {
 3415        let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3416        if !other_selections.is_empty() {
 3417            self.selections
 3418                .change_with(&self.display_snapshot(cx), |selections| {
 3419                    selections.select_anchors(other_selections);
 3420                });
 3421        }
 3422
 3423        let other_subscription = cx.subscribe(&other, |this, other, other_evt, cx| {
 3424            if let EditorEvent::SelectionsChanged { local: true } = other_evt {
 3425                let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3426                if other_selections.is_empty() {
 3427                    return;
 3428                }
 3429                let snapshot = this.display_snapshot(cx);
 3430                this.selections.change_with(&snapshot, |selections| {
 3431                    selections.select_anchors(other_selections);
 3432                });
 3433            }
 3434        });
 3435
 3436        let this_subscription = cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| {
 3437            if let EditorEvent::SelectionsChanged { local: true } = this_evt {
 3438                let these_selections = this.selections.disjoint_anchors().to_vec();
 3439                if these_selections.is_empty() {
 3440                    return;
 3441                }
 3442                other.update(cx, |other_editor, cx| {
 3443                    let snapshot = other_editor.display_snapshot(cx);
 3444                    other_editor
 3445                        .selections
 3446                        .change_with(&snapshot, |selections| {
 3447                            selections.select_anchors(these_selections);
 3448                        })
 3449                });
 3450            }
 3451        });
 3452
 3453        Subscription::join(other_subscription, this_subscription)
 3454    }
 3455
 3456    fn unfold_buffers_with_selections(&mut self, cx: &mut Context<Self>) {
 3457        if self.buffer().read(cx).is_singleton() {
 3458            return;
 3459        }
 3460        let snapshot = self.buffer.read(cx).snapshot(cx);
 3461        let buffer_ids: HashSet<BufferId> = self
 3462            .selections
 3463            .disjoint_anchor_ranges()
 3464            .flat_map(|range| snapshot.buffer_ids_for_range(range))
 3465            .collect();
 3466        for buffer_id in buffer_ids {
 3467            self.unfold_buffer(buffer_id, cx);
 3468        }
 3469    }
 3470
 3471    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 3472    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 3473    /// effects of selection change occur at the end of the transaction.
 3474    pub fn change_selections<R>(
 3475        &mut self,
 3476        effects: SelectionEffects,
 3477        window: &mut Window,
 3478        cx: &mut Context<Self>,
 3479        change: impl FnOnce(&mut MutableSelectionsCollection<'_, '_>) -> R,
 3480    ) -> R {
 3481        let snapshot = self.display_snapshot(cx);
 3482        if let Some(state) = &mut self.deferred_selection_effects_state {
 3483            state.effects.scroll = effects.scroll.or(state.effects.scroll);
 3484            state.effects.completions = effects.completions;
 3485            state.effects.nav_history = effects.nav_history.or(state.effects.nav_history);
 3486            let (changed, result) = self.selections.change_with(&snapshot, change);
 3487            state.changed |= changed;
 3488            return result;
 3489        }
 3490        let mut state = DeferredSelectionEffectsState {
 3491            changed: false,
 3492            effects,
 3493            old_cursor_position: self.selections.newest_anchor().head(),
 3494            history_entry: SelectionHistoryEntry {
 3495                selections: self.selections.disjoint_anchors_arc(),
 3496                select_next_state: self.select_next_state.clone(),
 3497                select_prev_state: self.select_prev_state.clone(),
 3498                add_selections_state: self.add_selections_state.clone(),
 3499            },
 3500        };
 3501        let (changed, result) = self.selections.change_with(&snapshot, change);
 3502        state.changed = state.changed || changed;
 3503        if self.defer_selection_effects {
 3504            self.deferred_selection_effects_state = Some(state);
 3505        } else {
 3506            self.apply_selection_effects(state, window, cx);
 3507        }
 3508        result
 3509    }
 3510
 3511    /// Defers the effects of selection change, so that the effects of multiple calls to
 3512    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3513    /// to selection history and the state of popovers based on selection position aren't
 3514    /// erroneously updated.
 3515    pub fn with_selection_effects_deferred<R>(
 3516        &mut self,
 3517        window: &mut Window,
 3518        cx: &mut Context<Self>,
 3519        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3520    ) -> R {
 3521        let already_deferred = self.defer_selection_effects;
 3522        self.defer_selection_effects = true;
 3523        let result = update(self, window, cx);
 3524        if !already_deferred {
 3525            self.defer_selection_effects = false;
 3526            if let Some(state) = self.deferred_selection_effects_state.take() {
 3527                self.apply_selection_effects(state, window, cx);
 3528            }
 3529        }
 3530        result
 3531    }
 3532
 3533    fn apply_selection_effects(
 3534        &mut self,
 3535        state: DeferredSelectionEffectsState,
 3536        window: &mut Window,
 3537        cx: &mut Context<Self>,
 3538    ) {
 3539        if state.changed {
 3540            self.selection_history.push(state.history_entry);
 3541
 3542            if let Some(autoscroll) = state.effects.scroll {
 3543                self.request_autoscroll(autoscroll, cx);
 3544            }
 3545
 3546            let old_cursor_position = &state.old_cursor_position;
 3547
 3548            self.selections_did_change(true, old_cursor_position, state.effects, window, cx);
 3549
 3550            if self.should_open_signature_help_automatically(old_cursor_position, cx) {
 3551                self.show_signature_help(&ShowSignatureHelp, window, cx);
 3552            }
 3553        }
 3554    }
 3555
 3556    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3557    where
 3558        I: IntoIterator<Item = (Range<S>, T)>,
 3559        S: ToOffset,
 3560        T: Into<Arc<str>>,
 3561    {
 3562        if self.read_only(cx) {
 3563            return;
 3564        }
 3565
 3566        self.buffer
 3567            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3568    }
 3569
 3570    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3571    where
 3572        I: IntoIterator<Item = (Range<S>, T)>,
 3573        S: ToOffset,
 3574        T: Into<Arc<str>>,
 3575    {
 3576        if self.read_only(cx) {
 3577            return;
 3578        }
 3579
 3580        self.buffer.update(cx, |buffer, cx| {
 3581            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3582        });
 3583    }
 3584
 3585    pub fn edit_with_block_indent<I, S, T>(
 3586        &mut self,
 3587        edits: I,
 3588        original_indent_columns: Vec<Option<u32>>,
 3589        cx: &mut Context<Self>,
 3590    ) where
 3591        I: IntoIterator<Item = (Range<S>, T)>,
 3592        S: ToOffset,
 3593        T: Into<Arc<str>>,
 3594    {
 3595        if self.read_only(cx) {
 3596            return;
 3597        }
 3598
 3599        self.buffer.update(cx, |buffer, cx| {
 3600            buffer.edit(
 3601                edits,
 3602                Some(AutoindentMode::Block {
 3603                    original_indent_columns,
 3604                }),
 3605                cx,
 3606            )
 3607        });
 3608    }
 3609
 3610    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3611        self.hide_context_menu(window, cx);
 3612
 3613        match phase {
 3614            SelectPhase::Begin {
 3615                position,
 3616                add,
 3617                click_count,
 3618            } => self.begin_selection(position, add, click_count, window, cx),
 3619            SelectPhase::BeginColumnar {
 3620                position,
 3621                goal_column,
 3622                reset,
 3623                mode,
 3624            } => self.begin_columnar_selection(position, goal_column, reset, mode, window, cx),
 3625            SelectPhase::Extend {
 3626                position,
 3627                click_count,
 3628            } => self.extend_selection(position, click_count, window, cx),
 3629            SelectPhase::Update {
 3630                position,
 3631                goal_column,
 3632                scroll_delta,
 3633            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3634            SelectPhase::End => self.end_selection(window, cx),
 3635        }
 3636    }
 3637
 3638    fn extend_selection(
 3639        &mut self,
 3640        position: DisplayPoint,
 3641        click_count: usize,
 3642        window: &mut Window,
 3643        cx: &mut Context<Self>,
 3644    ) {
 3645        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3646        let tail = self.selections.newest::<usize>(&display_map).tail();
 3647        let click_count = click_count.max(match self.selections.select_mode() {
 3648            SelectMode::Character => 1,
 3649            SelectMode::Word(_) => 2,
 3650            SelectMode::Line(_) => 3,
 3651            SelectMode::All => 4,
 3652        });
 3653        self.begin_selection(position, false, click_count, window, cx);
 3654
 3655        let tail_anchor = display_map.buffer_snapshot().anchor_before(tail);
 3656
 3657        let current_selection = match self.selections.select_mode() {
 3658            SelectMode::Character | SelectMode::All => tail_anchor..tail_anchor,
 3659            SelectMode::Word(range) | SelectMode::Line(range) => range.clone(),
 3660        };
 3661
 3662        let mut pending_selection = self
 3663            .selections
 3664            .pending_anchor()
 3665            .cloned()
 3666            .expect("extend_selection not called with pending selection");
 3667
 3668        if pending_selection
 3669            .start
 3670            .cmp(&current_selection.start, display_map.buffer_snapshot())
 3671            == Ordering::Greater
 3672        {
 3673            pending_selection.start = current_selection.start;
 3674        }
 3675        if pending_selection
 3676            .end
 3677            .cmp(&current_selection.end, display_map.buffer_snapshot())
 3678            == Ordering::Less
 3679        {
 3680            pending_selection.end = current_selection.end;
 3681            pending_selection.reversed = true;
 3682        }
 3683
 3684        let mut pending_mode = self.selections.pending_mode().unwrap();
 3685        match &mut pending_mode {
 3686            SelectMode::Word(range) | SelectMode::Line(range) => *range = current_selection,
 3687            _ => {}
 3688        }
 3689
 3690        let effects = if EditorSettings::get_global(cx).autoscroll_on_clicks {
 3691            SelectionEffects::scroll(Autoscroll::fit())
 3692        } else {
 3693            SelectionEffects::no_scroll()
 3694        };
 3695
 3696        self.change_selections(effects, window, cx, |s| {
 3697            s.set_pending(pending_selection.clone(), pending_mode);
 3698            s.set_is_extending(true);
 3699        });
 3700    }
 3701
 3702    fn begin_selection(
 3703        &mut self,
 3704        position: DisplayPoint,
 3705        add: bool,
 3706        click_count: usize,
 3707        window: &mut Window,
 3708        cx: &mut Context<Self>,
 3709    ) {
 3710        if !self.focus_handle.is_focused(window) {
 3711            self.last_focused_descendant = None;
 3712            window.focus(&self.focus_handle);
 3713        }
 3714
 3715        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3716        let buffer = display_map.buffer_snapshot();
 3717        let position = display_map.clip_point(position, Bias::Left);
 3718
 3719        let start;
 3720        let end;
 3721        let mode;
 3722        let mut auto_scroll;
 3723        match click_count {
 3724            1 => {
 3725                start = buffer.anchor_before(position.to_point(&display_map));
 3726                end = start;
 3727                mode = SelectMode::Character;
 3728                auto_scroll = true;
 3729            }
 3730            2 => {
 3731                let position = display_map
 3732                    .clip_point(position, Bias::Left)
 3733                    .to_offset(&display_map, Bias::Left);
 3734                let (range, _) = buffer.surrounding_word(position, None);
 3735                start = buffer.anchor_before(range.start);
 3736                end = buffer.anchor_before(range.end);
 3737                mode = SelectMode::Word(start..end);
 3738                auto_scroll = true;
 3739            }
 3740            3 => {
 3741                let position = display_map
 3742                    .clip_point(position, Bias::Left)
 3743                    .to_point(&display_map);
 3744                let line_start = display_map.prev_line_boundary(position).0;
 3745                let next_line_start = buffer.clip_point(
 3746                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3747                    Bias::Left,
 3748                );
 3749                start = buffer.anchor_before(line_start);
 3750                end = buffer.anchor_before(next_line_start);
 3751                mode = SelectMode::Line(start..end);
 3752                auto_scroll = true;
 3753            }
 3754            _ => {
 3755                start = buffer.anchor_before(0);
 3756                end = buffer.anchor_before(buffer.len());
 3757                mode = SelectMode::All;
 3758                auto_scroll = false;
 3759            }
 3760        }
 3761        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3762
 3763        let point_to_delete: Option<usize> = {
 3764            let selected_points: Vec<Selection<Point>> =
 3765                self.selections.disjoint_in_range(start..end, &display_map);
 3766
 3767            if !add || click_count > 1 {
 3768                None
 3769            } else if !selected_points.is_empty() {
 3770                Some(selected_points[0].id)
 3771            } else {
 3772                let clicked_point_already_selected =
 3773                    self.selections.disjoint_anchors().iter().find(|selection| {
 3774                        selection.start.to_point(buffer) == start.to_point(buffer)
 3775                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3776                    });
 3777
 3778                clicked_point_already_selected.map(|selection| selection.id)
 3779            }
 3780        };
 3781
 3782        let selections_count = self.selections.count();
 3783        let effects = if auto_scroll {
 3784            SelectionEffects::default()
 3785        } else {
 3786            SelectionEffects::no_scroll()
 3787        };
 3788
 3789        self.change_selections(effects, window, cx, |s| {
 3790            if let Some(point_to_delete) = point_to_delete {
 3791                s.delete(point_to_delete);
 3792
 3793                if selections_count == 1 {
 3794                    s.set_pending_anchor_range(start..end, mode);
 3795                }
 3796            } else {
 3797                if !add {
 3798                    s.clear_disjoint();
 3799                }
 3800
 3801                s.set_pending_anchor_range(start..end, mode);
 3802            }
 3803        });
 3804    }
 3805
 3806    fn begin_columnar_selection(
 3807        &mut self,
 3808        position: DisplayPoint,
 3809        goal_column: u32,
 3810        reset: bool,
 3811        mode: ColumnarMode,
 3812        window: &mut Window,
 3813        cx: &mut Context<Self>,
 3814    ) {
 3815        if !self.focus_handle.is_focused(window) {
 3816            self.last_focused_descendant = None;
 3817            window.focus(&self.focus_handle);
 3818        }
 3819
 3820        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3821
 3822        if reset {
 3823            let pointer_position = display_map
 3824                .buffer_snapshot()
 3825                .anchor_before(position.to_point(&display_map));
 3826
 3827            self.change_selections(
 3828                SelectionEffects::scroll(Autoscroll::newest()),
 3829                window,
 3830                cx,
 3831                |s| {
 3832                    s.clear_disjoint();
 3833                    s.set_pending_anchor_range(
 3834                        pointer_position..pointer_position,
 3835                        SelectMode::Character,
 3836                    );
 3837                },
 3838            );
 3839        };
 3840
 3841        let tail = self.selections.newest::<Point>(&display_map).tail();
 3842        let selection_anchor = display_map.buffer_snapshot().anchor_before(tail);
 3843        self.columnar_selection_state = match mode {
 3844            ColumnarMode::FromMouse => Some(ColumnarSelectionState::FromMouse {
 3845                selection_tail: selection_anchor,
 3846                display_point: if reset {
 3847                    if position.column() != goal_column {
 3848                        Some(DisplayPoint::new(position.row(), goal_column))
 3849                    } else {
 3850                        None
 3851                    }
 3852                } else {
 3853                    None
 3854                },
 3855            }),
 3856            ColumnarMode::FromSelection => Some(ColumnarSelectionState::FromSelection {
 3857                selection_tail: selection_anchor,
 3858            }),
 3859        };
 3860
 3861        if !reset {
 3862            self.select_columns(position, goal_column, &display_map, window, cx);
 3863        }
 3864    }
 3865
 3866    fn update_selection(
 3867        &mut self,
 3868        position: DisplayPoint,
 3869        goal_column: u32,
 3870        scroll_delta: gpui::Point<f32>,
 3871        window: &mut Window,
 3872        cx: &mut Context<Self>,
 3873    ) {
 3874        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3875
 3876        if self.columnar_selection_state.is_some() {
 3877            self.select_columns(position, goal_column, &display_map, window, cx);
 3878        } else if let Some(mut pending) = self.selections.pending_anchor().cloned() {
 3879            let buffer = display_map.buffer_snapshot();
 3880            let head;
 3881            let tail;
 3882            let mode = self.selections.pending_mode().unwrap();
 3883            match &mode {
 3884                SelectMode::Character => {
 3885                    head = position.to_point(&display_map);
 3886                    tail = pending.tail().to_point(buffer);
 3887                }
 3888                SelectMode::Word(original_range) => {
 3889                    let offset = display_map
 3890                        .clip_point(position, Bias::Left)
 3891                        .to_offset(&display_map, Bias::Left);
 3892                    let original_range = original_range.to_offset(buffer);
 3893
 3894                    let head_offset = if buffer.is_inside_word(offset, None)
 3895                        || original_range.contains(&offset)
 3896                    {
 3897                        let (word_range, _) = buffer.surrounding_word(offset, None);
 3898                        if word_range.start < original_range.start {
 3899                            word_range.start
 3900                        } else {
 3901                            word_range.end
 3902                        }
 3903                    } else {
 3904                        offset
 3905                    };
 3906
 3907                    head = head_offset.to_point(buffer);
 3908                    if head_offset <= original_range.start {
 3909                        tail = original_range.end.to_point(buffer);
 3910                    } else {
 3911                        tail = original_range.start.to_point(buffer);
 3912                    }
 3913                }
 3914                SelectMode::Line(original_range) => {
 3915                    let original_range = original_range.to_point(display_map.buffer_snapshot());
 3916
 3917                    let position = display_map
 3918                        .clip_point(position, Bias::Left)
 3919                        .to_point(&display_map);
 3920                    let line_start = display_map.prev_line_boundary(position).0;
 3921                    let next_line_start = buffer.clip_point(
 3922                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3923                        Bias::Left,
 3924                    );
 3925
 3926                    if line_start < original_range.start {
 3927                        head = line_start
 3928                    } else {
 3929                        head = next_line_start
 3930                    }
 3931
 3932                    if head <= original_range.start {
 3933                        tail = original_range.end;
 3934                    } else {
 3935                        tail = original_range.start;
 3936                    }
 3937                }
 3938                SelectMode::All => {
 3939                    return;
 3940                }
 3941            };
 3942
 3943            if head < tail {
 3944                pending.start = buffer.anchor_before(head);
 3945                pending.end = buffer.anchor_before(tail);
 3946                pending.reversed = true;
 3947            } else {
 3948                pending.start = buffer.anchor_before(tail);
 3949                pending.end = buffer.anchor_before(head);
 3950                pending.reversed = false;
 3951            }
 3952
 3953            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3954                s.set_pending(pending.clone(), mode);
 3955            });
 3956        } else {
 3957            log::error!("update_selection dispatched with no pending selection");
 3958            return;
 3959        }
 3960
 3961        self.apply_scroll_delta(scroll_delta, window, cx);
 3962        cx.notify();
 3963    }
 3964
 3965    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3966        self.columnar_selection_state.take();
 3967        if let Some(pending_mode) = self.selections.pending_mode() {
 3968            let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
 3969            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3970                s.select(selections);
 3971                s.clear_pending();
 3972                if s.is_extending() {
 3973                    s.set_is_extending(false);
 3974                } else {
 3975                    s.set_select_mode(pending_mode);
 3976                }
 3977            });
 3978        }
 3979    }
 3980
 3981    fn select_columns(
 3982        &mut self,
 3983        head: DisplayPoint,
 3984        goal_column: u32,
 3985        display_map: &DisplaySnapshot,
 3986        window: &mut Window,
 3987        cx: &mut Context<Self>,
 3988    ) {
 3989        let Some(columnar_state) = self.columnar_selection_state.as_ref() else {
 3990            return;
 3991        };
 3992
 3993        let tail = match columnar_state {
 3994            ColumnarSelectionState::FromMouse {
 3995                selection_tail,
 3996                display_point,
 3997            } => display_point.unwrap_or_else(|| selection_tail.to_display_point(display_map)),
 3998            ColumnarSelectionState::FromSelection { selection_tail } => {
 3999                selection_tail.to_display_point(display_map)
 4000            }
 4001        };
 4002
 4003        let start_row = cmp::min(tail.row(), head.row());
 4004        let end_row = cmp::max(tail.row(), head.row());
 4005        let start_column = cmp::min(tail.column(), goal_column);
 4006        let end_column = cmp::max(tail.column(), goal_column);
 4007        let reversed = start_column < tail.column();
 4008
 4009        let selection_ranges = (start_row.0..=end_row.0)
 4010            .map(DisplayRow)
 4011            .filter_map(|row| {
 4012                if (matches!(columnar_state, ColumnarSelectionState::FromMouse { .. })
 4013                    || start_column <= display_map.line_len(row))
 4014                    && !display_map.is_block_line(row)
 4015                {
 4016                    let start = display_map
 4017                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 4018                        .to_point(display_map);
 4019                    let end = display_map
 4020                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 4021                        .to_point(display_map);
 4022                    if reversed {
 4023                        Some(end..start)
 4024                    } else {
 4025                        Some(start..end)
 4026                    }
 4027                } else {
 4028                    None
 4029                }
 4030            })
 4031            .collect::<Vec<_>>();
 4032        if selection_ranges.is_empty() {
 4033            return;
 4034        }
 4035
 4036        let ranges = match columnar_state {
 4037            ColumnarSelectionState::FromMouse { .. } => {
 4038                let mut non_empty_ranges = selection_ranges
 4039                    .iter()
 4040                    .filter(|selection_range| selection_range.start != selection_range.end)
 4041                    .peekable();
 4042                if non_empty_ranges.peek().is_some() {
 4043                    non_empty_ranges.cloned().collect()
 4044                } else {
 4045                    selection_ranges
 4046                }
 4047            }
 4048            _ => selection_ranges,
 4049        };
 4050
 4051        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 4052            s.select_ranges(ranges);
 4053        });
 4054        cx.notify();
 4055    }
 4056
 4057    pub fn has_non_empty_selection(&self, snapshot: &DisplaySnapshot) -> bool {
 4058        self.selections
 4059            .all_adjusted(snapshot)
 4060            .iter()
 4061            .any(|selection| !selection.is_empty())
 4062    }
 4063
 4064    pub fn has_pending_nonempty_selection(&self) -> bool {
 4065        let pending_nonempty_selection = match self.selections.pending_anchor() {
 4066            Some(Selection { start, end, .. }) => start != end,
 4067            None => false,
 4068        };
 4069
 4070        pending_nonempty_selection
 4071            || (self.columnar_selection_state.is_some()
 4072                && self.selections.disjoint_anchors().len() > 1)
 4073    }
 4074
 4075    pub fn has_pending_selection(&self) -> bool {
 4076        self.selections.pending_anchor().is_some() || self.columnar_selection_state.is_some()
 4077    }
 4078
 4079    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 4080        self.selection_mark_mode = false;
 4081        self.selection_drag_state = SelectionDragState::None;
 4082
 4083        if self.dismiss_menus_and_popups(true, window, cx) {
 4084            cx.notify();
 4085            return;
 4086        }
 4087        if self.clear_expanded_diff_hunks(cx) {
 4088            cx.notify();
 4089            return;
 4090        }
 4091        if self.show_git_blame_gutter {
 4092            self.show_git_blame_gutter = false;
 4093            cx.notify();
 4094            return;
 4095        }
 4096
 4097        if self.mode.is_full()
 4098            && self.change_selections(Default::default(), window, cx, |s| s.try_cancel())
 4099        {
 4100            cx.notify();
 4101            return;
 4102        }
 4103
 4104        cx.propagate();
 4105    }
 4106
 4107    pub fn dismiss_menus_and_popups(
 4108        &mut self,
 4109        is_user_requested: bool,
 4110        window: &mut Window,
 4111        cx: &mut Context<Self>,
 4112    ) -> bool {
 4113        if self.take_rename(false, window, cx).is_some() {
 4114            return true;
 4115        }
 4116
 4117        if self.hide_blame_popover(true, cx) {
 4118            return true;
 4119        }
 4120
 4121        if hide_hover(self, cx) {
 4122            return true;
 4123        }
 4124
 4125        if self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape) {
 4126            return true;
 4127        }
 4128
 4129        if self.hide_context_menu(window, cx).is_some() {
 4130            return true;
 4131        }
 4132
 4133        if self.mouse_context_menu.take().is_some() {
 4134            return true;
 4135        }
 4136
 4137        if is_user_requested && self.discard_edit_prediction(true, cx) {
 4138            return true;
 4139        }
 4140
 4141        if self.snippet_stack.pop().is_some() {
 4142            return true;
 4143        }
 4144
 4145        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 4146            self.dismiss_diagnostics(cx);
 4147            return true;
 4148        }
 4149
 4150        false
 4151    }
 4152
 4153    fn linked_editing_ranges_for(
 4154        &self,
 4155        selection: Range<text::Anchor>,
 4156        cx: &App,
 4157    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 4158        if self.linked_edit_ranges.is_empty() {
 4159            return None;
 4160        }
 4161        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 4162            selection.end.buffer_id.and_then(|end_buffer_id| {
 4163                if selection.start.buffer_id != Some(end_buffer_id) {
 4164                    return None;
 4165                }
 4166                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 4167                let snapshot = buffer.read(cx).snapshot();
 4168                self.linked_edit_ranges
 4169                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 4170                    .map(|ranges| (ranges, snapshot, buffer))
 4171            })?;
 4172        use text::ToOffset as TO;
 4173        // find offset from the start of current range to current cursor position
 4174        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 4175
 4176        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 4177        let start_difference = start_offset - start_byte_offset;
 4178        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 4179        let end_difference = end_offset - start_byte_offset;
 4180        // Current range has associated linked ranges.
 4181        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4182        for range in linked_ranges.iter() {
 4183            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 4184            let end_offset = start_offset + end_difference;
 4185            let start_offset = start_offset + start_difference;
 4186            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 4187                continue;
 4188            }
 4189            if self.selections.disjoint_anchor_ranges().any(|s| {
 4190                if s.start.buffer_id != selection.start.buffer_id
 4191                    || s.end.buffer_id != selection.end.buffer_id
 4192                {
 4193                    return false;
 4194                }
 4195                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 4196                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 4197            }) {
 4198                continue;
 4199            }
 4200            let start = buffer_snapshot.anchor_after(start_offset);
 4201            let end = buffer_snapshot.anchor_after(end_offset);
 4202            linked_edits
 4203                .entry(buffer.clone())
 4204                .or_default()
 4205                .push(start..end);
 4206        }
 4207        Some(linked_edits)
 4208    }
 4209
 4210    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4211        let text: Arc<str> = text.into();
 4212
 4213        if self.read_only(cx) {
 4214            return;
 4215        }
 4216
 4217        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4218
 4219        self.unfold_buffers_with_selections(cx);
 4220
 4221        let selections = self.selections.all_adjusted(&self.display_snapshot(cx));
 4222        let mut bracket_inserted = false;
 4223        let mut edits = Vec::new();
 4224        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4225        let mut new_selections = Vec::with_capacity(selections.len());
 4226        let mut new_autoclose_regions = Vec::new();
 4227        let snapshot = self.buffer.read(cx).read(cx);
 4228        let mut clear_linked_edit_ranges = false;
 4229
 4230        for (selection, autoclose_region) in
 4231            self.selections_with_autoclose_regions(selections, &snapshot)
 4232        {
 4233            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 4234                // Determine if the inserted text matches the opening or closing
 4235                // bracket of any of this language's bracket pairs.
 4236                let mut bracket_pair = None;
 4237                let mut is_bracket_pair_start = false;
 4238                let mut is_bracket_pair_end = false;
 4239                if !text.is_empty() {
 4240                    let mut bracket_pair_matching_end = None;
 4241                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 4242                    //  and they are removing the character that triggered IME popup.
 4243                    for (pair, enabled) in scope.brackets() {
 4244                        if !pair.close && !pair.surround {
 4245                            continue;
 4246                        }
 4247
 4248                        if enabled && pair.start.ends_with(text.as_ref()) {
 4249                            let prefix_len = pair.start.len() - text.len();
 4250                            let preceding_text_matches_prefix = prefix_len == 0
 4251                                || (selection.start.column >= (prefix_len as u32)
 4252                                    && snapshot.contains_str_at(
 4253                                        Point::new(
 4254                                            selection.start.row,
 4255                                            selection.start.column - (prefix_len as u32),
 4256                                        ),
 4257                                        &pair.start[..prefix_len],
 4258                                    ));
 4259                            if preceding_text_matches_prefix {
 4260                                bracket_pair = Some(pair.clone());
 4261                                is_bracket_pair_start = true;
 4262                                break;
 4263                            }
 4264                        }
 4265                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 4266                        {
 4267                            // take first bracket pair matching end, but don't break in case a later bracket
 4268                            // pair matches start
 4269                            bracket_pair_matching_end = Some(pair.clone());
 4270                        }
 4271                    }
 4272                    if let Some(end) = bracket_pair_matching_end
 4273                        && bracket_pair.is_none()
 4274                    {
 4275                        bracket_pair = Some(end);
 4276                        is_bracket_pair_end = true;
 4277                    }
 4278                }
 4279
 4280                if let Some(bracket_pair) = bracket_pair {
 4281                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 4282                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 4283                    let auto_surround =
 4284                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 4285                    if selection.is_empty() {
 4286                        if is_bracket_pair_start {
 4287                            // If the inserted text is a suffix of an opening bracket and the
 4288                            // selection is preceded by the rest of the opening bracket, then
 4289                            // insert the closing bracket.
 4290                            let following_text_allows_autoclose = snapshot
 4291                                .chars_at(selection.start)
 4292                                .next()
 4293                                .is_none_or(|c| scope.should_autoclose_before(c));
 4294
 4295                            let preceding_text_allows_autoclose = selection.start.column == 0
 4296                                || snapshot
 4297                                    .reversed_chars_at(selection.start)
 4298                                    .next()
 4299                                    .is_none_or(|c| {
 4300                                        bracket_pair.start != bracket_pair.end
 4301                                            || !snapshot
 4302                                                .char_classifier_at(selection.start)
 4303                                                .is_word(c)
 4304                                    });
 4305
 4306                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 4307                                && bracket_pair.start.len() == 1
 4308                            {
 4309                                let target = bracket_pair.start.chars().next().unwrap();
 4310                                let current_line_count = snapshot
 4311                                    .reversed_chars_at(selection.start)
 4312                                    .take_while(|&c| c != '\n')
 4313                                    .filter(|&c| c == target)
 4314                                    .count();
 4315                                current_line_count % 2 == 1
 4316                            } else {
 4317                                false
 4318                            };
 4319
 4320                            if autoclose
 4321                                && bracket_pair.close
 4322                                && following_text_allows_autoclose
 4323                                && preceding_text_allows_autoclose
 4324                                && !is_closing_quote
 4325                            {
 4326                                let anchor = snapshot.anchor_before(selection.end);
 4327                                new_selections.push((selection.map(|_| anchor), text.len()));
 4328                                new_autoclose_regions.push((
 4329                                    anchor,
 4330                                    text.len(),
 4331                                    selection.id,
 4332                                    bracket_pair.clone(),
 4333                                ));
 4334                                edits.push((
 4335                                    selection.range(),
 4336                                    format!("{}{}", text, bracket_pair.end).into(),
 4337                                ));
 4338                                bracket_inserted = true;
 4339                                continue;
 4340                            }
 4341                        }
 4342
 4343                        if let Some(region) = autoclose_region {
 4344                            // If the selection is followed by an auto-inserted closing bracket,
 4345                            // then don't insert that closing bracket again; just move the selection
 4346                            // past the closing bracket.
 4347                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 4348                                && text.as_ref() == region.pair.end.as_str()
 4349                                && snapshot.contains_str_at(region.range.end, text.as_ref());
 4350                            if should_skip {
 4351                                let anchor = snapshot.anchor_after(selection.end);
 4352                                new_selections
 4353                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 4354                                continue;
 4355                            }
 4356                        }
 4357
 4358                        let always_treat_brackets_as_autoclosed = snapshot
 4359                            .language_settings_at(selection.start, cx)
 4360                            .always_treat_brackets_as_autoclosed;
 4361                        if always_treat_brackets_as_autoclosed
 4362                            && is_bracket_pair_end
 4363                            && snapshot.contains_str_at(selection.end, text.as_ref())
 4364                        {
 4365                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 4366                            // and the inserted text is a closing bracket and the selection is followed
 4367                            // by the closing bracket then move the selection past the closing bracket.
 4368                            let anchor = snapshot.anchor_after(selection.end);
 4369                            new_selections.push((selection.map(|_| anchor), text.len()));
 4370                            continue;
 4371                        }
 4372                    }
 4373                    // If an opening bracket is 1 character long and is typed while
 4374                    // text is selected, then surround that text with the bracket pair.
 4375                    else if auto_surround
 4376                        && bracket_pair.surround
 4377                        && is_bracket_pair_start
 4378                        && bracket_pair.start.chars().count() == 1
 4379                    {
 4380                        edits.push((selection.start..selection.start, text.clone()));
 4381                        edits.push((
 4382                            selection.end..selection.end,
 4383                            bracket_pair.end.as_str().into(),
 4384                        ));
 4385                        bracket_inserted = true;
 4386                        new_selections.push((
 4387                            Selection {
 4388                                id: selection.id,
 4389                                start: snapshot.anchor_after(selection.start),
 4390                                end: snapshot.anchor_before(selection.end),
 4391                                reversed: selection.reversed,
 4392                                goal: selection.goal,
 4393                            },
 4394                            0,
 4395                        ));
 4396                        continue;
 4397                    }
 4398                }
 4399            }
 4400
 4401            if self.auto_replace_emoji_shortcode
 4402                && selection.is_empty()
 4403                && text.as_ref().ends_with(':')
 4404                && let Some(possible_emoji_short_code) =
 4405                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 4406                && !possible_emoji_short_code.is_empty()
 4407                && let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code)
 4408            {
 4409                let emoji_shortcode_start = Point::new(
 4410                    selection.start.row,
 4411                    selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 4412                );
 4413
 4414                // Remove shortcode from buffer
 4415                edits.push((
 4416                    emoji_shortcode_start..selection.start,
 4417                    "".to_string().into(),
 4418                ));
 4419                new_selections.push((
 4420                    Selection {
 4421                        id: selection.id,
 4422                        start: snapshot.anchor_after(emoji_shortcode_start),
 4423                        end: snapshot.anchor_before(selection.start),
 4424                        reversed: selection.reversed,
 4425                        goal: selection.goal,
 4426                    },
 4427                    0,
 4428                ));
 4429
 4430                // Insert emoji
 4431                let selection_start_anchor = snapshot.anchor_after(selection.start);
 4432                new_selections.push((selection.map(|_| selection_start_anchor), 0));
 4433                edits.push((selection.start..selection.end, emoji.to_string().into()));
 4434
 4435                continue;
 4436            }
 4437
 4438            // If not handling any auto-close operation, then just replace the selected
 4439            // text with the given input and move the selection to the end of the
 4440            // newly inserted text.
 4441            let anchor = snapshot.anchor_after(selection.end);
 4442            if !self.linked_edit_ranges.is_empty() {
 4443                let start_anchor = snapshot.anchor_before(selection.start);
 4444
 4445                let is_word_char = text.chars().next().is_none_or(|char| {
 4446                    let classifier = snapshot
 4447                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 4448                        .scope_context(Some(CharScopeContext::LinkedEdit));
 4449                    classifier.is_word(char)
 4450                });
 4451
 4452                if is_word_char {
 4453                    if let Some(ranges) = self
 4454                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 4455                    {
 4456                        for (buffer, edits) in ranges {
 4457                            linked_edits
 4458                                .entry(buffer.clone())
 4459                                .or_default()
 4460                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 4461                        }
 4462                    }
 4463                } else {
 4464                    clear_linked_edit_ranges = true;
 4465                }
 4466            }
 4467
 4468            new_selections.push((selection.map(|_| anchor), 0));
 4469            edits.push((selection.start..selection.end, text.clone()));
 4470        }
 4471
 4472        drop(snapshot);
 4473
 4474        self.transact(window, cx, |this, window, cx| {
 4475            if clear_linked_edit_ranges {
 4476                this.linked_edit_ranges.clear();
 4477            }
 4478            let initial_buffer_versions =
 4479                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 4480
 4481            this.buffer.update(cx, |buffer, cx| {
 4482                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 4483            });
 4484            for (buffer, edits) in linked_edits {
 4485                buffer.update(cx, |buffer, cx| {
 4486                    let snapshot = buffer.snapshot();
 4487                    let edits = edits
 4488                        .into_iter()
 4489                        .map(|(range, text)| {
 4490                            use text::ToPoint as TP;
 4491                            let end_point = TP::to_point(&range.end, &snapshot);
 4492                            let start_point = TP::to_point(&range.start, &snapshot);
 4493                            (start_point..end_point, text)
 4494                        })
 4495                        .sorted_by_key(|(range, _)| range.start);
 4496                    buffer.edit(edits, None, cx);
 4497                })
 4498            }
 4499            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 4500            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 4501            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 4502            let new_selections =
 4503                resolve_selections_wrapping_blocks::<usize, _>(new_anchor_selections, &map)
 4504                    .zip(new_selection_deltas)
 4505                    .map(|(selection, delta)| Selection {
 4506                        id: selection.id,
 4507                        start: selection.start + delta,
 4508                        end: selection.end + delta,
 4509                        reversed: selection.reversed,
 4510                        goal: SelectionGoal::None,
 4511                    })
 4512                    .collect::<Vec<_>>();
 4513
 4514            let mut i = 0;
 4515            for (position, delta, selection_id, pair) in new_autoclose_regions {
 4516                let position = position.to_offset(map.buffer_snapshot()) + delta;
 4517                let start = map.buffer_snapshot().anchor_before(position);
 4518                let end = map.buffer_snapshot().anchor_after(position);
 4519                while let Some(existing_state) = this.autoclose_regions.get(i) {
 4520                    match existing_state
 4521                        .range
 4522                        .start
 4523                        .cmp(&start, map.buffer_snapshot())
 4524                    {
 4525                        Ordering::Less => i += 1,
 4526                        Ordering::Greater => break,
 4527                        Ordering::Equal => {
 4528                            match end.cmp(&existing_state.range.end, map.buffer_snapshot()) {
 4529                                Ordering::Less => i += 1,
 4530                                Ordering::Equal => break,
 4531                                Ordering::Greater => break,
 4532                            }
 4533                        }
 4534                    }
 4535                }
 4536                this.autoclose_regions.insert(
 4537                    i,
 4538                    AutocloseRegion {
 4539                        selection_id,
 4540                        range: start..end,
 4541                        pair,
 4542                    },
 4543                );
 4544            }
 4545
 4546            let had_active_edit_prediction = this.has_active_edit_prediction();
 4547            this.change_selections(
 4548                SelectionEffects::scroll(Autoscroll::fit()).completions(false),
 4549                window,
 4550                cx,
 4551                |s| s.select(new_selections),
 4552            );
 4553
 4554            if !bracket_inserted
 4555                && let Some(on_type_format_task) =
 4556                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 4557            {
 4558                on_type_format_task.detach_and_log_err(cx);
 4559            }
 4560
 4561            let editor_settings = EditorSettings::get_global(cx);
 4562            if bracket_inserted
 4563                && (editor_settings.auto_signature_help
 4564                    || editor_settings.show_signature_help_after_edits)
 4565            {
 4566                this.show_signature_help(&ShowSignatureHelp, window, cx);
 4567            }
 4568
 4569            let trigger_in_words =
 4570                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
 4571            if this.hard_wrap.is_some() {
 4572                let latest: Range<Point> = this.selections.newest(&map).range();
 4573                if latest.is_empty()
 4574                    && this
 4575                        .buffer()
 4576                        .read(cx)
 4577                        .snapshot(cx)
 4578                        .line_len(MultiBufferRow(latest.start.row))
 4579                        == latest.start.column
 4580                {
 4581                    this.rewrap_impl(
 4582                        RewrapOptions {
 4583                            override_language_settings: true,
 4584                            preserve_existing_whitespace: true,
 4585                        },
 4586                        cx,
 4587                    )
 4588                }
 4589            }
 4590            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4591            refresh_linked_ranges(this, window, cx);
 4592            this.refresh_edit_prediction(true, false, window, cx);
 4593            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4594        });
 4595    }
 4596
 4597    fn find_possible_emoji_shortcode_at_position(
 4598        snapshot: &MultiBufferSnapshot,
 4599        position: Point,
 4600    ) -> Option<String> {
 4601        let mut chars = Vec::new();
 4602        let mut found_colon = false;
 4603        for char in snapshot.reversed_chars_at(position).take(100) {
 4604            // Found a possible emoji shortcode in the middle of the buffer
 4605            if found_colon {
 4606                if char.is_whitespace() {
 4607                    chars.reverse();
 4608                    return Some(chars.iter().collect());
 4609                }
 4610                // If the previous character is not a whitespace, we are in the middle of a word
 4611                // and we only want to complete the shortcode if the word is made up of other emojis
 4612                let mut containing_word = String::new();
 4613                for ch in snapshot
 4614                    .reversed_chars_at(position)
 4615                    .skip(chars.len() + 1)
 4616                    .take(100)
 4617                {
 4618                    if ch.is_whitespace() {
 4619                        break;
 4620                    }
 4621                    containing_word.push(ch);
 4622                }
 4623                let containing_word = containing_word.chars().rev().collect::<String>();
 4624                if util::word_consists_of_emojis(containing_word.as_str()) {
 4625                    chars.reverse();
 4626                    return Some(chars.iter().collect());
 4627                }
 4628            }
 4629
 4630            if char.is_whitespace() || !char.is_ascii() {
 4631                return None;
 4632            }
 4633            if char == ':' {
 4634                found_colon = true;
 4635            } else {
 4636                chars.push(char);
 4637            }
 4638        }
 4639        // Found a possible emoji shortcode at the beginning of the buffer
 4640        chars.reverse();
 4641        Some(chars.iter().collect())
 4642    }
 4643
 4644    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4645        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4646        self.transact(window, cx, |this, window, cx| {
 4647            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4648                let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
 4649                let multi_buffer = this.buffer.read(cx);
 4650                let buffer = multi_buffer.snapshot(cx);
 4651                selections
 4652                    .iter()
 4653                    .map(|selection| {
 4654                        let start_point = selection.start.to_point(&buffer);
 4655                        let mut existing_indent =
 4656                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4657                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4658                        let start = selection.start;
 4659                        let end = selection.end;
 4660                        let selection_is_empty = start == end;
 4661                        let language_scope = buffer.language_scope_at(start);
 4662                        let (
 4663                            comment_delimiter,
 4664                            doc_delimiter,
 4665                            insert_extra_newline,
 4666                            indent_on_newline,
 4667                            indent_on_extra_newline,
 4668                        ) = if let Some(language) = &language_scope {
 4669                            let mut insert_extra_newline =
 4670                                insert_extra_newline_brackets(&buffer, start..end, language)
 4671                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 4672
 4673                            // Comment extension on newline is allowed only for cursor selections
 4674                            let comment_delimiter = maybe!({
 4675                                if !selection_is_empty {
 4676                                    return None;
 4677                                }
 4678
 4679                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4680                                    return None;
 4681                                }
 4682
 4683                                let delimiters = language.line_comment_prefixes();
 4684                                let max_len_of_delimiter =
 4685                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 4686                                let (snapshot, range) =
 4687                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4688
 4689                                let num_of_whitespaces = snapshot
 4690                                    .chars_for_range(range.clone())
 4691                                    .take_while(|c| c.is_whitespace())
 4692                                    .count();
 4693                                let comment_candidate = snapshot
 4694                                    .chars_for_range(range.clone())
 4695                                    .skip(num_of_whitespaces)
 4696                                    .take(max_len_of_delimiter)
 4697                                    .collect::<String>();
 4698                                let (delimiter, trimmed_len) = delimiters
 4699                                    .iter()
 4700                                    .filter_map(|delimiter| {
 4701                                        let prefix = delimiter.trim_end();
 4702                                        if comment_candidate.starts_with(prefix) {
 4703                                            Some((delimiter, prefix.len()))
 4704                                        } else {
 4705                                            None
 4706                                        }
 4707                                    })
 4708                                    .max_by_key(|(_, len)| *len)?;
 4709
 4710                                if let Some(BlockCommentConfig {
 4711                                    start: block_start, ..
 4712                                }) = language.block_comment()
 4713                                {
 4714                                    let block_start_trimmed = block_start.trim_end();
 4715                                    if block_start_trimmed.starts_with(delimiter.trim_end()) {
 4716                                        let line_content = snapshot
 4717                                            .chars_for_range(range)
 4718                                            .skip(num_of_whitespaces)
 4719                                            .take(block_start_trimmed.len())
 4720                                            .collect::<String>();
 4721
 4722                                        if line_content.starts_with(block_start_trimmed) {
 4723                                            return None;
 4724                                        }
 4725                                    }
 4726                                }
 4727
 4728                                let cursor_is_placed_after_comment_marker =
 4729                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 4730                                if cursor_is_placed_after_comment_marker {
 4731                                    Some(delimiter.clone())
 4732                                } else {
 4733                                    None
 4734                                }
 4735                            });
 4736
 4737                            let mut indent_on_newline = IndentSize::spaces(0);
 4738                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 4739
 4740                            let doc_delimiter = maybe!({
 4741                                if !selection_is_empty {
 4742                                    return None;
 4743                                }
 4744
 4745                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4746                                    return None;
 4747                                }
 4748
 4749                                let BlockCommentConfig {
 4750                                    start: start_tag,
 4751                                    end: end_tag,
 4752                                    prefix: delimiter,
 4753                                    tab_size: len,
 4754                                } = language.documentation_comment()?;
 4755                                let is_within_block_comment = buffer
 4756                                    .language_scope_at(start_point)
 4757                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4758                                if !is_within_block_comment {
 4759                                    return None;
 4760                                }
 4761
 4762                                let (snapshot, range) =
 4763                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4764
 4765                                let num_of_whitespaces = snapshot
 4766                                    .chars_for_range(range.clone())
 4767                                    .take_while(|c| c.is_whitespace())
 4768                                    .count();
 4769
 4770                                // 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.
 4771                                let column = start_point.column;
 4772                                let cursor_is_after_start_tag = {
 4773                                    let start_tag_len = start_tag.len();
 4774                                    let start_tag_line = snapshot
 4775                                        .chars_for_range(range.clone())
 4776                                        .skip(num_of_whitespaces)
 4777                                        .take(start_tag_len)
 4778                                        .collect::<String>();
 4779                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4780                                        num_of_whitespaces + start_tag_len <= column as usize
 4781                                    } else {
 4782                                        false
 4783                                    }
 4784                                };
 4785
 4786                                let cursor_is_after_delimiter = {
 4787                                    let delimiter_trim = delimiter.trim_end();
 4788                                    let delimiter_line = snapshot
 4789                                        .chars_for_range(range.clone())
 4790                                        .skip(num_of_whitespaces)
 4791                                        .take(delimiter_trim.len())
 4792                                        .collect::<String>();
 4793                                    if delimiter_line.starts_with(delimiter_trim) {
 4794                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4795                                    } else {
 4796                                        false
 4797                                    }
 4798                                };
 4799
 4800                                let cursor_is_before_end_tag_if_exists = {
 4801                                    let mut char_position = 0u32;
 4802                                    let mut end_tag_offset = None;
 4803
 4804                                    'outer: for chunk in snapshot.text_for_range(range) {
 4805                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4806                                            let chars_before_match =
 4807                                                chunk[..byte_pos].chars().count() as u32;
 4808                                            end_tag_offset =
 4809                                                Some(char_position + chars_before_match);
 4810                                            break 'outer;
 4811                                        }
 4812                                        char_position += chunk.chars().count() as u32;
 4813                                    }
 4814
 4815                                    if let Some(end_tag_offset) = end_tag_offset {
 4816                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4817                                        if cursor_is_after_start_tag {
 4818                                            if cursor_is_before_end_tag {
 4819                                                insert_extra_newline = true;
 4820                                            }
 4821                                            let cursor_is_at_start_of_end_tag =
 4822                                                column == end_tag_offset;
 4823                                            if cursor_is_at_start_of_end_tag {
 4824                                                indent_on_extra_newline.len = *len;
 4825                                            }
 4826                                        }
 4827                                        cursor_is_before_end_tag
 4828                                    } else {
 4829                                        true
 4830                                    }
 4831                                };
 4832
 4833                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4834                                    && cursor_is_before_end_tag_if_exists
 4835                                {
 4836                                    if cursor_is_after_start_tag {
 4837                                        indent_on_newline.len = *len;
 4838                                    }
 4839                                    Some(delimiter.clone())
 4840                                } else {
 4841                                    None
 4842                                }
 4843                            });
 4844
 4845                            (
 4846                                comment_delimiter,
 4847                                doc_delimiter,
 4848                                insert_extra_newline,
 4849                                indent_on_newline,
 4850                                indent_on_extra_newline,
 4851                            )
 4852                        } else {
 4853                            (
 4854                                None,
 4855                                None,
 4856                                false,
 4857                                IndentSize::default(),
 4858                                IndentSize::default(),
 4859                            )
 4860                        };
 4861
 4862                        let prevent_auto_indent = doc_delimiter.is_some();
 4863                        let delimiter = comment_delimiter.or(doc_delimiter);
 4864
 4865                        let capacity_for_delimiter =
 4866                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4867                        let mut new_text = String::with_capacity(
 4868                            1 + capacity_for_delimiter
 4869                                + existing_indent.len as usize
 4870                                + indent_on_newline.len as usize
 4871                                + indent_on_extra_newline.len as usize,
 4872                        );
 4873                        new_text.push('\n');
 4874                        new_text.extend(existing_indent.chars());
 4875                        new_text.extend(indent_on_newline.chars());
 4876
 4877                        if let Some(delimiter) = &delimiter {
 4878                            new_text.push_str(delimiter);
 4879                        }
 4880
 4881                        if insert_extra_newline {
 4882                            new_text.push('\n');
 4883                            new_text.extend(existing_indent.chars());
 4884                            new_text.extend(indent_on_extra_newline.chars());
 4885                        }
 4886
 4887                        let anchor = buffer.anchor_after(end);
 4888                        let new_selection = selection.map(|_| anchor);
 4889                        (
 4890                            ((start..end, new_text), prevent_auto_indent),
 4891                            (insert_extra_newline, new_selection),
 4892                        )
 4893                    })
 4894                    .unzip()
 4895            };
 4896
 4897            let mut auto_indent_edits = Vec::new();
 4898            let mut edits = Vec::new();
 4899            for (edit, prevent_auto_indent) in edits_with_flags {
 4900                if prevent_auto_indent {
 4901                    edits.push(edit);
 4902                } else {
 4903                    auto_indent_edits.push(edit);
 4904                }
 4905            }
 4906            if !edits.is_empty() {
 4907                this.edit(edits, cx);
 4908            }
 4909            if !auto_indent_edits.is_empty() {
 4910                this.edit_with_autoindent(auto_indent_edits, cx);
 4911            }
 4912
 4913            let buffer = this.buffer.read(cx).snapshot(cx);
 4914            let new_selections = selection_info
 4915                .into_iter()
 4916                .map(|(extra_newline_inserted, new_selection)| {
 4917                    let mut cursor = new_selection.end.to_point(&buffer);
 4918                    if extra_newline_inserted {
 4919                        cursor.row -= 1;
 4920                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4921                    }
 4922                    new_selection.map(|_| cursor)
 4923                })
 4924                .collect();
 4925
 4926            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
 4927            this.refresh_edit_prediction(true, false, window, cx);
 4928        });
 4929    }
 4930
 4931    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4932        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4933
 4934        let buffer = self.buffer.read(cx);
 4935        let snapshot = buffer.snapshot(cx);
 4936
 4937        let mut edits = Vec::new();
 4938        let mut rows = Vec::new();
 4939
 4940        for (rows_inserted, selection) in self
 4941            .selections
 4942            .all_adjusted(&self.display_snapshot(cx))
 4943            .into_iter()
 4944            .enumerate()
 4945        {
 4946            let cursor = selection.head();
 4947            let row = cursor.row;
 4948
 4949            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4950
 4951            let newline = "\n".to_string();
 4952            edits.push((start_of_line..start_of_line, newline));
 4953
 4954            rows.push(row + rows_inserted as u32);
 4955        }
 4956
 4957        self.transact(window, cx, |editor, window, cx| {
 4958            editor.edit(edits, cx);
 4959
 4960            editor.change_selections(Default::default(), window, cx, |s| {
 4961                let mut index = 0;
 4962                s.move_cursors_with(|map, _, _| {
 4963                    let row = rows[index];
 4964                    index += 1;
 4965
 4966                    let point = Point::new(row, 0);
 4967                    let boundary = map.next_line_boundary(point).1;
 4968                    let clipped = map.clip_point(boundary, Bias::Left);
 4969
 4970                    (clipped, SelectionGoal::None)
 4971                });
 4972            });
 4973
 4974            let mut indent_edits = Vec::new();
 4975            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4976            for row in rows {
 4977                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4978                for (row, indent) in indents {
 4979                    if indent.len == 0 {
 4980                        continue;
 4981                    }
 4982
 4983                    let text = match indent.kind {
 4984                        IndentKind::Space => " ".repeat(indent.len as usize),
 4985                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4986                    };
 4987                    let point = Point::new(row.0, 0);
 4988                    indent_edits.push((point..point, text));
 4989                }
 4990            }
 4991            editor.edit(indent_edits, cx);
 4992        });
 4993    }
 4994
 4995    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 4996        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4997
 4998        let buffer = self.buffer.read(cx);
 4999        let snapshot = buffer.snapshot(cx);
 5000
 5001        let mut edits = Vec::new();
 5002        let mut rows = Vec::new();
 5003        let mut rows_inserted = 0;
 5004
 5005        for selection in self.selections.all_adjusted(&self.display_snapshot(cx)) {
 5006            let cursor = selection.head();
 5007            let row = cursor.row;
 5008
 5009            let point = Point::new(row + 1, 0);
 5010            let start_of_line = snapshot.clip_point(point, Bias::Left);
 5011
 5012            let newline = "\n".to_string();
 5013            edits.push((start_of_line..start_of_line, newline));
 5014
 5015            rows_inserted += 1;
 5016            rows.push(row + rows_inserted);
 5017        }
 5018
 5019        self.transact(window, cx, |editor, window, cx| {
 5020            editor.edit(edits, cx);
 5021
 5022            editor.change_selections(Default::default(), window, cx, |s| {
 5023                let mut index = 0;
 5024                s.move_cursors_with(|map, _, _| {
 5025                    let row = rows[index];
 5026                    index += 1;
 5027
 5028                    let point = Point::new(row, 0);
 5029                    let boundary = map.next_line_boundary(point).1;
 5030                    let clipped = map.clip_point(boundary, Bias::Left);
 5031
 5032                    (clipped, SelectionGoal::None)
 5033                });
 5034            });
 5035
 5036            let mut indent_edits = Vec::new();
 5037            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 5038            for row in rows {
 5039                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 5040                for (row, indent) in indents {
 5041                    if indent.len == 0 {
 5042                        continue;
 5043                    }
 5044
 5045                    let text = match indent.kind {
 5046                        IndentKind::Space => " ".repeat(indent.len as usize),
 5047                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 5048                    };
 5049                    let point = Point::new(row.0, 0);
 5050                    indent_edits.push((point..point, text));
 5051                }
 5052            }
 5053            editor.edit(indent_edits, cx);
 5054        });
 5055    }
 5056
 5057    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 5058        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 5059            original_indent_columns: Vec::new(),
 5060        });
 5061        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 5062    }
 5063
 5064    fn insert_with_autoindent_mode(
 5065        &mut self,
 5066        text: &str,
 5067        autoindent_mode: Option<AutoindentMode>,
 5068        window: &mut Window,
 5069        cx: &mut Context<Self>,
 5070    ) {
 5071        if self.read_only(cx) {
 5072            return;
 5073        }
 5074
 5075        let text: Arc<str> = text.into();
 5076        self.transact(window, cx, |this, window, cx| {
 5077            let old_selections = this.selections.all_adjusted(&this.display_snapshot(cx));
 5078            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 5079                let anchors = {
 5080                    let snapshot = buffer.read(cx);
 5081                    old_selections
 5082                        .iter()
 5083                        .map(|s| {
 5084                            let anchor = snapshot.anchor_after(s.head());
 5085                            s.map(|_| anchor)
 5086                        })
 5087                        .collect::<Vec<_>>()
 5088                };
 5089                buffer.edit(
 5090                    old_selections
 5091                        .iter()
 5092                        .map(|s| (s.start..s.end, text.clone())),
 5093                    autoindent_mode,
 5094                    cx,
 5095                );
 5096                anchors
 5097            });
 5098
 5099            this.change_selections(Default::default(), window, cx, |s| {
 5100                s.select_anchors(selection_anchors);
 5101            });
 5102
 5103            cx.notify();
 5104        });
 5105    }
 5106
 5107    fn trigger_completion_on_input(
 5108        &mut self,
 5109        text: &str,
 5110        trigger_in_words: bool,
 5111        window: &mut Window,
 5112        cx: &mut Context<Self>,
 5113    ) {
 5114        let completions_source = self
 5115            .context_menu
 5116            .borrow()
 5117            .as_ref()
 5118            .and_then(|menu| match menu {
 5119                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 5120                CodeContextMenu::CodeActions(_) => None,
 5121            });
 5122
 5123        match completions_source {
 5124            Some(CompletionsMenuSource::Words { .. }) => {
 5125                self.open_or_update_completions_menu(
 5126                    Some(CompletionsMenuSource::Words {
 5127                        ignore_threshold: false,
 5128                    }),
 5129                    None,
 5130                    trigger_in_words,
 5131                    window,
 5132                    cx,
 5133                );
 5134            }
 5135            _ => self.open_or_update_completions_menu(
 5136                None,
 5137                Some(text.to_owned()).filter(|x| !x.is_empty()),
 5138                true,
 5139                window,
 5140                cx,
 5141            ),
 5142        }
 5143    }
 5144
 5145    /// If any empty selections is touching the start of its innermost containing autoclose
 5146    /// region, expand it to select the brackets.
 5147    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 5148        let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
 5149        let buffer = self.buffer.read(cx).read(cx);
 5150        let new_selections = self
 5151            .selections_with_autoclose_regions(selections, &buffer)
 5152            .map(|(mut selection, region)| {
 5153                if !selection.is_empty() {
 5154                    return selection;
 5155                }
 5156
 5157                if let Some(region) = region {
 5158                    let mut range = region.range.to_offset(&buffer);
 5159                    if selection.start == range.start && range.start >= region.pair.start.len() {
 5160                        range.start -= region.pair.start.len();
 5161                        if buffer.contains_str_at(range.start, &region.pair.start)
 5162                            && buffer.contains_str_at(range.end, &region.pair.end)
 5163                        {
 5164                            range.end += region.pair.end.len();
 5165                            selection.start = range.start;
 5166                            selection.end = range.end;
 5167
 5168                            return selection;
 5169                        }
 5170                    }
 5171                }
 5172
 5173                let always_treat_brackets_as_autoclosed = buffer
 5174                    .language_settings_at(selection.start, cx)
 5175                    .always_treat_brackets_as_autoclosed;
 5176
 5177                if !always_treat_brackets_as_autoclosed {
 5178                    return selection;
 5179                }
 5180
 5181                if let Some(scope) = buffer.language_scope_at(selection.start) {
 5182                    for (pair, enabled) in scope.brackets() {
 5183                        if !enabled || !pair.close {
 5184                            continue;
 5185                        }
 5186
 5187                        if buffer.contains_str_at(selection.start, &pair.end) {
 5188                            let pair_start_len = pair.start.len();
 5189                            if buffer.contains_str_at(
 5190                                selection.start.saturating_sub(pair_start_len),
 5191                                &pair.start,
 5192                            ) {
 5193                                selection.start -= pair_start_len;
 5194                                selection.end += pair.end.len();
 5195
 5196                                return selection;
 5197                            }
 5198                        }
 5199                    }
 5200                }
 5201
 5202                selection
 5203            })
 5204            .collect();
 5205
 5206        drop(buffer);
 5207        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
 5208            selections.select(new_selections)
 5209        });
 5210    }
 5211
 5212    /// Iterate the given selections, and for each one, find the smallest surrounding
 5213    /// autoclose region. This uses the ordering of the selections and the autoclose
 5214    /// regions to avoid repeated comparisons.
 5215    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 5216        &'a self,
 5217        selections: impl IntoIterator<Item = Selection<D>>,
 5218        buffer: &'a MultiBufferSnapshot,
 5219    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 5220        let mut i = 0;
 5221        let mut regions = self.autoclose_regions.as_slice();
 5222        selections.into_iter().map(move |selection| {
 5223            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 5224
 5225            let mut enclosing = None;
 5226            while let Some(pair_state) = regions.get(i) {
 5227                if pair_state.range.end.to_offset(buffer) < range.start {
 5228                    regions = &regions[i + 1..];
 5229                    i = 0;
 5230                } else if pair_state.range.start.to_offset(buffer) > range.end {
 5231                    break;
 5232                } else {
 5233                    if pair_state.selection_id == selection.id {
 5234                        enclosing = Some(pair_state);
 5235                    }
 5236                    i += 1;
 5237                }
 5238            }
 5239
 5240            (selection, enclosing)
 5241        })
 5242    }
 5243
 5244    /// Remove any autoclose regions that no longer contain their selection or have invalid anchors in ranges.
 5245    fn invalidate_autoclose_regions(
 5246        &mut self,
 5247        mut selections: &[Selection<Anchor>],
 5248        buffer: &MultiBufferSnapshot,
 5249    ) {
 5250        self.autoclose_regions.retain(|state| {
 5251            if !state.range.start.is_valid(buffer) || !state.range.end.is_valid(buffer) {
 5252                return false;
 5253            }
 5254
 5255            let mut i = 0;
 5256            while let Some(selection) = selections.get(i) {
 5257                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 5258                    selections = &selections[1..];
 5259                    continue;
 5260                }
 5261                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 5262                    break;
 5263                }
 5264                if selection.id == state.selection_id {
 5265                    return true;
 5266                } else {
 5267                    i += 1;
 5268                }
 5269            }
 5270            false
 5271        });
 5272    }
 5273
 5274    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 5275        let offset = position.to_offset(buffer);
 5276        let (word_range, kind) =
 5277            buffer.surrounding_word(offset, Some(CharScopeContext::Completion));
 5278        if offset > word_range.start && kind == Some(CharKind::Word) {
 5279            Some(
 5280                buffer
 5281                    .text_for_range(word_range.start..offset)
 5282                    .collect::<String>(),
 5283            )
 5284        } else {
 5285            None
 5286        }
 5287    }
 5288
 5289    pub fn visible_excerpts(
 5290        &self,
 5291        cx: &mut Context<Editor>,
 5292    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 5293        let Some(project) = self.project() else {
 5294            return HashMap::default();
 5295        };
 5296        let project = project.read(cx);
 5297        let multi_buffer = self.buffer().read(cx);
 5298        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 5299        let multi_buffer_visible_start = self
 5300            .scroll_manager
 5301            .anchor()
 5302            .anchor
 5303            .to_point(&multi_buffer_snapshot);
 5304        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 5305            multi_buffer_visible_start
 5306                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 5307            Bias::Left,
 5308        );
 5309        multi_buffer_snapshot
 5310            .range_to_buffer_ranges(multi_buffer_visible_start..multi_buffer_visible_end)
 5311            .into_iter()
 5312            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 5313            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 5314                let buffer_file = project::File::from_dyn(buffer.file())?;
 5315                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 5316                let worktree_entry = buffer_worktree
 5317                    .read(cx)
 5318                    .entry_for_id(buffer_file.project_entry_id()?)?;
 5319                if worktree_entry.is_ignored {
 5320                    None
 5321                } else {
 5322                    Some((
 5323                        excerpt_id,
 5324                        (
 5325                            multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5326                            buffer.version().clone(),
 5327                            excerpt_visible_range,
 5328                        ),
 5329                    ))
 5330                }
 5331            })
 5332            .collect()
 5333    }
 5334
 5335    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 5336        TextLayoutDetails {
 5337            text_system: window.text_system().clone(),
 5338            editor_style: self.style.clone().unwrap(),
 5339            rem_size: window.rem_size(),
 5340            scroll_anchor: self.scroll_manager.anchor(),
 5341            visible_rows: self.visible_line_count(),
 5342            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 5343        }
 5344    }
 5345
 5346    fn trigger_on_type_formatting(
 5347        &self,
 5348        input: String,
 5349        window: &mut Window,
 5350        cx: &mut Context<Self>,
 5351    ) -> Option<Task<Result<()>>> {
 5352        if input.len() != 1 {
 5353            return None;
 5354        }
 5355
 5356        let project = self.project()?;
 5357        let position = self.selections.newest_anchor().head();
 5358        let (buffer, buffer_position) = self
 5359            .buffer
 5360            .read(cx)
 5361            .text_anchor_for_position(position, cx)?;
 5362
 5363        let settings = language_settings::language_settings(
 5364            buffer
 5365                .read(cx)
 5366                .language_at(buffer_position)
 5367                .map(|l| l.name()),
 5368            buffer.read(cx).file(),
 5369            cx,
 5370        );
 5371        if !settings.use_on_type_format {
 5372            return None;
 5373        }
 5374
 5375        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5376        // hence we do LSP request & edit on host side only — add formats to host's history.
 5377        let push_to_lsp_host_history = true;
 5378        // If this is not the host, append its history with new edits.
 5379        let push_to_client_history = project.read(cx).is_via_collab();
 5380
 5381        let on_type_formatting = project.update(cx, |project, cx| {
 5382            project.on_type_format(
 5383                buffer.clone(),
 5384                buffer_position,
 5385                input,
 5386                push_to_lsp_host_history,
 5387                cx,
 5388            )
 5389        });
 5390        Some(cx.spawn_in(window, async move |editor, cx| {
 5391            if let Some(transaction) = on_type_formatting.await? {
 5392                if push_to_client_history {
 5393                    buffer
 5394                        .update(cx, |buffer, _| {
 5395                            buffer.push_transaction(transaction, Instant::now());
 5396                            buffer.finalize_last_transaction();
 5397                        })
 5398                        .ok();
 5399                }
 5400                editor.update(cx, |editor, cx| {
 5401                    editor.refresh_document_highlights(cx);
 5402                })?;
 5403            }
 5404            Ok(())
 5405        }))
 5406    }
 5407
 5408    pub fn show_word_completions(
 5409        &mut self,
 5410        _: &ShowWordCompletions,
 5411        window: &mut Window,
 5412        cx: &mut Context<Self>,
 5413    ) {
 5414        self.open_or_update_completions_menu(
 5415            Some(CompletionsMenuSource::Words {
 5416                ignore_threshold: true,
 5417            }),
 5418            None,
 5419            false,
 5420            window,
 5421            cx,
 5422        );
 5423    }
 5424
 5425    pub fn show_completions(
 5426        &mut self,
 5427        _: &ShowCompletions,
 5428        window: &mut Window,
 5429        cx: &mut Context<Self>,
 5430    ) {
 5431        self.open_or_update_completions_menu(None, None, false, window, cx);
 5432    }
 5433
 5434    fn open_or_update_completions_menu(
 5435        &mut self,
 5436        requested_source: Option<CompletionsMenuSource>,
 5437        trigger: Option<String>,
 5438        trigger_in_words: bool,
 5439        window: &mut Window,
 5440        cx: &mut Context<Self>,
 5441    ) {
 5442        if self.pending_rename.is_some() {
 5443            return;
 5444        }
 5445
 5446        let completions_source = self
 5447            .context_menu
 5448            .borrow()
 5449            .as_ref()
 5450            .and_then(|menu| match menu {
 5451                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 5452                CodeContextMenu::CodeActions(_) => None,
 5453            });
 5454
 5455        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5456
 5457        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5458        // inserted and selected. To handle that case, the start of the selection is used so that
 5459        // the menu starts with all choices.
 5460        let position = self
 5461            .selections
 5462            .newest_anchor()
 5463            .start
 5464            .bias_right(&multibuffer_snapshot);
 5465        if position.diff_base_anchor.is_some() {
 5466            return;
 5467        }
 5468        let buffer_position = multibuffer_snapshot.anchor_before(position);
 5469        let Some(buffer) = buffer_position
 5470            .buffer_id
 5471            .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
 5472        else {
 5473            return;
 5474        };
 5475        let buffer_snapshot = buffer.read(cx).snapshot();
 5476
 5477        let query: Option<Arc<String>> =
 5478            Self::completion_query(&multibuffer_snapshot, buffer_position)
 5479                .map(|query| query.into());
 5480
 5481        drop(multibuffer_snapshot);
 5482
 5483        // Hide the current completions menu when query is empty. Without this, cached
 5484        // completions from before the trigger char may be reused (#32774).
 5485        if query.is_none() {
 5486            let menu_is_open = matches!(
 5487                self.context_menu.borrow().as_ref(),
 5488                Some(CodeContextMenu::Completions(_))
 5489            );
 5490            if menu_is_open {
 5491                self.hide_context_menu(window, cx);
 5492            }
 5493        }
 5494
 5495        let mut ignore_word_threshold = false;
 5496        let provider = match requested_source {
 5497            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5498            Some(CompletionsMenuSource::Words { ignore_threshold }) => {
 5499                ignore_word_threshold = ignore_threshold;
 5500                None
 5501            }
 5502            Some(CompletionsMenuSource::SnippetChoices)
 5503            | Some(CompletionsMenuSource::SnippetsOnly) => {
 5504                log::error!("bug: SnippetChoices requested_source is not handled");
 5505                None
 5506            }
 5507        };
 5508
 5509        let sort_completions = provider
 5510            .as_ref()
 5511            .is_some_and(|provider| provider.sort_completions());
 5512
 5513        let filter_completions = provider
 5514            .as_ref()
 5515            .is_none_or(|provider| provider.filter_completions());
 5516
 5517        let was_snippets_only = matches!(
 5518            completions_source,
 5519            Some(CompletionsMenuSource::SnippetsOnly)
 5520        );
 5521
 5522        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5523            if filter_completions {
 5524                menu.filter(
 5525                    query.clone().unwrap_or_default(),
 5526                    buffer_position.text_anchor,
 5527                    &buffer,
 5528                    provider.clone(),
 5529                    window,
 5530                    cx,
 5531                );
 5532            }
 5533            // When `is_incomplete` is false, no need to re-query completions when the current query
 5534            // is a suffix of the initial query.
 5535            let was_complete = !menu.is_incomplete;
 5536            if was_complete && !was_snippets_only {
 5537                // If the new query is a suffix of the old query (typing more characters) and
 5538                // the previous result was complete, the existing completions can be filtered.
 5539                //
 5540                // Note that snippet completions are always complete.
 5541                let query_matches = match (&menu.initial_query, &query) {
 5542                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5543                    (None, _) => true,
 5544                    _ => false,
 5545                };
 5546                if query_matches {
 5547                    let position_matches = if menu.initial_position == position {
 5548                        true
 5549                    } else {
 5550                        let snapshot = self.buffer.read(cx).read(cx);
 5551                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5552                    };
 5553                    if position_matches {
 5554                        return;
 5555                    }
 5556                }
 5557            }
 5558        };
 5559
 5560        let Anchor {
 5561            excerpt_id: buffer_excerpt_id,
 5562            text_anchor: buffer_position,
 5563            ..
 5564        } = buffer_position;
 5565
 5566        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5567            buffer_snapshot.surrounding_word(buffer_position, None)
 5568        {
 5569            let word_to_exclude = buffer_snapshot
 5570                .text_for_range(word_range.clone())
 5571                .collect::<String>();
 5572            (
 5573                buffer_snapshot.anchor_before(word_range.start)
 5574                    ..buffer_snapshot.anchor_after(buffer_position),
 5575                Some(word_to_exclude),
 5576            )
 5577        } else {
 5578            (buffer_position..buffer_position, None)
 5579        };
 5580
 5581        let language = buffer_snapshot
 5582            .language_at(buffer_position)
 5583            .map(|language| language.name());
 5584
 5585        let completion_settings = language_settings(language.clone(), buffer_snapshot.file(), cx)
 5586            .completions
 5587            .clone();
 5588
 5589        let show_completion_documentation = buffer_snapshot
 5590            .settings_at(buffer_position, cx)
 5591            .show_completion_documentation;
 5592
 5593        // The document can be large, so stay in reasonable bounds when searching for words,
 5594        // otherwise completion pop-up might be slow to appear.
 5595        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5596        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5597        let min_word_search = buffer_snapshot.clip_point(
 5598            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5599            Bias::Left,
 5600        );
 5601        let max_word_search = buffer_snapshot.clip_point(
 5602            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5603            Bias::Right,
 5604        );
 5605        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5606            ..buffer_snapshot.point_to_offset(max_word_search);
 5607
 5608        let skip_digits = query
 5609            .as_ref()
 5610            .is_none_or(|query| !query.chars().any(|c| c.is_digit(10)));
 5611
 5612        let load_provider_completions = provider.as_ref().is_some_and(|provider| {
 5613            trigger.as_ref().is_none_or(|trigger| {
 5614                provider.is_completion_trigger(
 5615                    &buffer,
 5616                    position.text_anchor,
 5617                    trigger,
 5618                    trigger_in_words,
 5619                    completions_source.is_some(),
 5620                    cx,
 5621                )
 5622            })
 5623        });
 5624
 5625        let provider_responses = if let Some(provider) = &provider
 5626            && load_provider_completions
 5627        {
 5628            let trigger_character =
 5629                trigger.filter(|trigger| buffer.read(cx).completion_triggers().contains(trigger));
 5630            let completion_context = CompletionContext {
 5631                trigger_kind: match &trigger_character {
 5632                    Some(_) => CompletionTriggerKind::TRIGGER_CHARACTER,
 5633                    None => CompletionTriggerKind::INVOKED,
 5634                },
 5635                trigger_character,
 5636            };
 5637
 5638            provider.completions(
 5639                buffer_excerpt_id,
 5640                &buffer,
 5641                buffer_position,
 5642                completion_context,
 5643                window,
 5644                cx,
 5645            )
 5646        } else {
 5647            Task::ready(Ok(Vec::new()))
 5648        };
 5649
 5650        let load_word_completions = if !self.word_completions_enabled {
 5651            false
 5652        } else if requested_source
 5653            == Some(CompletionsMenuSource::Words {
 5654                ignore_threshold: true,
 5655            })
 5656        {
 5657            true
 5658        } else {
 5659            load_provider_completions
 5660                && completion_settings.words != WordsCompletionMode::Disabled
 5661                && (ignore_word_threshold || {
 5662                    let words_min_length = completion_settings.words_min_length;
 5663                    // check whether word has at least `words_min_length` characters
 5664                    let query_chars = query.iter().flat_map(|q| q.chars());
 5665                    query_chars.take(words_min_length).count() == words_min_length
 5666                })
 5667        };
 5668
 5669        let mut words = if load_word_completions {
 5670            cx.background_spawn({
 5671                let buffer_snapshot = buffer_snapshot.clone();
 5672                async move {
 5673                    buffer_snapshot.words_in_range(WordsQuery {
 5674                        fuzzy_contents: None,
 5675                        range: word_search_range,
 5676                        skip_digits,
 5677                    })
 5678                }
 5679            })
 5680        } else {
 5681            Task::ready(BTreeMap::default())
 5682        };
 5683
 5684        let snippets = if let Some(provider) = &provider
 5685            && provider.show_snippets()
 5686            && let Some(project) = self.project()
 5687        {
 5688            let char_classifier = buffer_snapshot
 5689                .char_classifier_at(buffer_position)
 5690                .scope_context(Some(CharScopeContext::Completion));
 5691            project.update(cx, |project, cx| {
 5692                snippet_completions(project, &buffer, buffer_position, char_classifier, cx)
 5693            })
 5694        } else {
 5695            Task::ready(Ok(CompletionResponse {
 5696                completions: Vec::new(),
 5697                display_options: Default::default(),
 5698                is_incomplete: false,
 5699            }))
 5700        };
 5701
 5702        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5703
 5704        let id = post_inc(&mut self.next_completion_id);
 5705        let task = cx.spawn_in(window, async move |editor, cx| {
 5706            let Ok(()) = editor.update(cx, |this, _| {
 5707                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5708            }) else {
 5709                return;
 5710            };
 5711
 5712            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5713            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5714            let mut completions = Vec::new();
 5715            let mut is_incomplete = false;
 5716            let mut display_options: Option<CompletionDisplayOptions> = None;
 5717            if let Some(provider_responses) = provider_responses.await.log_err()
 5718                && !provider_responses.is_empty()
 5719            {
 5720                for response in provider_responses {
 5721                    completions.extend(response.completions);
 5722                    is_incomplete = is_incomplete || response.is_incomplete;
 5723                    match display_options.as_mut() {
 5724                        None => {
 5725                            display_options = Some(response.display_options);
 5726                        }
 5727                        Some(options) => options.merge(&response.display_options),
 5728                    }
 5729                }
 5730                if completion_settings.words == WordsCompletionMode::Fallback {
 5731                    words = Task::ready(BTreeMap::default());
 5732                }
 5733            }
 5734            let display_options = display_options.unwrap_or_default();
 5735
 5736            let mut words = words.await;
 5737            if let Some(word_to_exclude) = &word_to_exclude {
 5738                words.remove(word_to_exclude);
 5739            }
 5740            for lsp_completion in &completions {
 5741                words.remove(&lsp_completion.new_text);
 5742            }
 5743            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5744                replace_range: word_replace_range.clone(),
 5745                new_text: word.clone(),
 5746                label: CodeLabel::plain(word, None),
 5747                match_start: None,
 5748                snippet_deduplication_key: None,
 5749                icon_path: None,
 5750                documentation: None,
 5751                source: CompletionSource::BufferWord {
 5752                    word_range,
 5753                    resolved: false,
 5754                },
 5755                insert_text_mode: Some(InsertTextMode::AS_IS),
 5756                confirm: None,
 5757            }));
 5758
 5759            completions.extend(
 5760                snippets
 5761                    .await
 5762                    .into_iter()
 5763                    .flat_map(|response| response.completions),
 5764            );
 5765
 5766            let menu = if completions.is_empty() {
 5767                None
 5768            } else {
 5769                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5770                    let languages = editor
 5771                        .workspace
 5772                        .as_ref()
 5773                        .and_then(|(workspace, _)| workspace.upgrade())
 5774                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5775                    let menu = CompletionsMenu::new(
 5776                        id,
 5777                        requested_source.unwrap_or(if load_provider_completions {
 5778                            CompletionsMenuSource::Normal
 5779                        } else {
 5780                            CompletionsMenuSource::SnippetsOnly
 5781                        }),
 5782                        sort_completions,
 5783                        show_completion_documentation,
 5784                        position,
 5785                        query.clone(),
 5786                        is_incomplete,
 5787                        buffer.clone(),
 5788                        completions.into(),
 5789                        display_options,
 5790                        snippet_sort_order,
 5791                        languages,
 5792                        language,
 5793                        cx,
 5794                    );
 5795
 5796                    let query = if filter_completions { query } else { None };
 5797                    let matches_task = menu.do_async_filtering(
 5798                        query.unwrap_or_default(),
 5799                        buffer_position,
 5800                        &buffer,
 5801                        cx,
 5802                    );
 5803                    (menu, matches_task)
 5804                }) else {
 5805                    return;
 5806                };
 5807
 5808                let matches = matches_task.await;
 5809
 5810                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5811                    // Newer menu already set, so exit.
 5812                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5813                        editor.context_menu.borrow().as_ref()
 5814                        && prev_menu.id > id
 5815                    {
 5816                        return;
 5817                    };
 5818
 5819                    // Only valid to take prev_menu because either the new menu is immediately set
 5820                    // below, or the menu is hidden.
 5821                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5822                        editor.context_menu.borrow_mut().take()
 5823                    {
 5824                        let position_matches =
 5825                            if prev_menu.initial_position == menu.initial_position {
 5826                                true
 5827                            } else {
 5828                                let snapshot = editor.buffer.read(cx).read(cx);
 5829                                prev_menu.initial_position.to_offset(&snapshot)
 5830                                    == menu.initial_position.to_offset(&snapshot)
 5831                            };
 5832                        if position_matches {
 5833                            // Preserve markdown cache before `set_filter_results` because it will
 5834                            // try to populate the documentation cache.
 5835                            menu.preserve_markdown_cache(prev_menu);
 5836                        }
 5837                    };
 5838
 5839                    menu.set_filter_results(matches, provider, window, cx);
 5840                }) else {
 5841                    return;
 5842                };
 5843
 5844                menu.visible().then_some(menu)
 5845            };
 5846
 5847            editor
 5848                .update_in(cx, |editor, window, cx| {
 5849                    if editor.focus_handle.is_focused(window)
 5850                        && let Some(menu) = menu
 5851                    {
 5852                        *editor.context_menu.borrow_mut() =
 5853                            Some(CodeContextMenu::Completions(menu));
 5854
 5855                        crate::hover_popover::hide_hover(editor, cx);
 5856                        if editor.show_edit_predictions_in_menu() {
 5857                            editor.update_visible_edit_prediction(window, cx);
 5858                        } else {
 5859                            editor.discard_edit_prediction(false, cx);
 5860                        }
 5861
 5862                        cx.notify();
 5863                        return;
 5864                    }
 5865
 5866                    if editor.completion_tasks.len() <= 1 {
 5867                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 5868                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5869                        // If it was already hidden and we don't show edit predictions in the menu,
 5870                        // we should also show the edit prediction when available.
 5871                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5872                            editor.update_visible_edit_prediction(window, cx);
 5873                        }
 5874                    }
 5875                })
 5876                .ok();
 5877        });
 5878
 5879        self.completion_tasks.push((id, task));
 5880    }
 5881
 5882    #[cfg(feature = "test-support")]
 5883    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5884        let menu = self.context_menu.borrow();
 5885        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5886            let completions = menu.completions.borrow();
 5887            Some(completions.to_vec())
 5888        } else {
 5889            None
 5890        }
 5891    }
 5892
 5893    pub fn with_completions_menu_matching_id<R>(
 5894        &self,
 5895        id: CompletionId,
 5896        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 5897    ) -> R {
 5898        let mut context_menu = self.context_menu.borrow_mut();
 5899        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 5900            return f(None);
 5901        };
 5902        if completions_menu.id != id {
 5903            return f(None);
 5904        }
 5905        f(Some(completions_menu))
 5906    }
 5907
 5908    pub fn confirm_completion(
 5909        &mut self,
 5910        action: &ConfirmCompletion,
 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(action.item_ix, CompletionIntent::Complete, window, cx)
 5916    }
 5917
 5918    pub fn confirm_completion_insert(
 5919        &mut self,
 5920        _: &ConfirmCompletionInsert,
 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(None, CompletionIntent::CompleteWithInsert, window, cx)
 5926    }
 5927
 5928    pub fn confirm_completion_replace(
 5929        &mut self,
 5930        _: &ConfirmCompletionReplace,
 5931        window: &mut Window,
 5932        cx: &mut Context<Self>,
 5933    ) -> Option<Task<Result<()>>> {
 5934        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5935        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5936    }
 5937
 5938    pub fn compose_completion(
 5939        &mut self,
 5940        action: &ComposeCompletion,
 5941        window: &mut Window,
 5942        cx: &mut Context<Self>,
 5943    ) -> Option<Task<Result<()>>> {
 5944        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5945        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5946    }
 5947
 5948    fn do_completion(
 5949        &mut self,
 5950        item_ix: Option<usize>,
 5951        intent: CompletionIntent,
 5952        window: &mut Window,
 5953        cx: &mut Context<Editor>,
 5954    ) -> Option<Task<Result<()>>> {
 5955        use language::ToOffset as _;
 5956
 5957        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5958        else {
 5959            return None;
 5960        };
 5961
 5962        let candidate_id = {
 5963            let entries = completions_menu.entries.borrow();
 5964            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5965            if self.show_edit_predictions_in_menu() {
 5966                self.discard_edit_prediction(true, cx);
 5967            }
 5968            mat.candidate_id
 5969        };
 5970
 5971        let completion = completions_menu
 5972            .completions
 5973            .borrow()
 5974            .get(candidate_id)?
 5975            .clone();
 5976        cx.stop_propagation();
 5977
 5978        let buffer_handle = completions_menu.buffer.clone();
 5979
 5980        let CompletionEdit {
 5981            new_text,
 5982            snippet,
 5983            replace_range,
 5984        } = process_completion_for_edit(
 5985            &completion,
 5986            intent,
 5987            &buffer_handle,
 5988            &completions_menu.initial_position.text_anchor,
 5989            cx,
 5990        );
 5991
 5992        let buffer = buffer_handle.read(cx);
 5993        let snapshot = self.buffer.read(cx).snapshot(cx);
 5994        let newest_anchor = self.selections.newest_anchor();
 5995        let replace_range_multibuffer = {
 5996            let mut excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 5997            excerpt.map_range_from_buffer(replace_range.clone())
 5998        };
 5999        if snapshot.buffer_id_for_anchor(newest_anchor.head()) != Some(buffer.remote_id()) {
 6000            return None;
 6001        }
 6002
 6003        let old_text = buffer
 6004            .text_for_range(replace_range.clone())
 6005            .collect::<String>();
 6006        let lookbehind = newest_anchor
 6007            .start
 6008            .text_anchor
 6009            .to_offset(buffer)
 6010            .saturating_sub(replace_range.start);
 6011        let lookahead = replace_range
 6012            .end
 6013            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 6014        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 6015        let suffix = &old_text[lookbehind.min(old_text.len())..];
 6016
 6017        let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
 6018        let mut ranges = Vec::new();
 6019        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 6020
 6021        for selection in &selections {
 6022            let range = if selection.id == newest_anchor.id {
 6023                replace_range_multibuffer.clone()
 6024            } else {
 6025                let mut range = selection.range();
 6026
 6027                // if prefix is present, don't duplicate it
 6028                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 6029                    range.start = range.start.saturating_sub(lookbehind);
 6030
 6031                    // if suffix is also present, mimic the newest cursor and replace it
 6032                    if selection.id != newest_anchor.id
 6033                        && snapshot.contains_str_at(range.end, suffix)
 6034                    {
 6035                        range.end += lookahead;
 6036                    }
 6037                }
 6038                range
 6039            };
 6040
 6041            ranges.push(range.clone());
 6042
 6043            if !self.linked_edit_ranges.is_empty() {
 6044                let start_anchor = snapshot.anchor_before(range.start);
 6045                let end_anchor = snapshot.anchor_after(range.end);
 6046                if let Some(ranges) = self
 6047                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 6048                {
 6049                    for (buffer, edits) in ranges {
 6050                        linked_edits
 6051                            .entry(buffer.clone())
 6052                            .or_default()
 6053                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 6054                    }
 6055                }
 6056            }
 6057        }
 6058
 6059        let common_prefix_len = old_text
 6060            .chars()
 6061            .zip(new_text.chars())
 6062            .take_while(|(a, b)| a == b)
 6063            .map(|(a, _)| a.len_utf8())
 6064            .sum::<usize>();
 6065
 6066        cx.emit(EditorEvent::InputHandled {
 6067            utf16_range_to_replace: None,
 6068            text: new_text[common_prefix_len..].into(),
 6069        });
 6070
 6071        self.transact(window, cx, |editor, window, cx| {
 6072            if let Some(mut snippet) = snippet {
 6073                snippet.text = new_text.to_string();
 6074                editor
 6075                    .insert_snippet(&ranges, snippet, window, cx)
 6076                    .log_err();
 6077            } else {
 6078                editor.buffer.update(cx, |multi_buffer, cx| {
 6079                    let auto_indent = match completion.insert_text_mode {
 6080                        Some(InsertTextMode::AS_IS) => None,
 6081                        _ => editor.autoindent_mode.clone(),
 6082                    };
 6083                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 6084                    multi_buffer.edit(edits, auto_indent, cx);
 6085                });
 6086            }
 6087            for (buffer, edits) in linked_edits {
 6088                buffer.update(cx, |buffer, cx| {
 6089                    let snapshot = buffer.snapshot();
 6090                    let edits = edits
 6091                        .into_iter()
 6092                        .map(|(range, text)| {
 6093                            use text::ToPoint as TP;
 6094                            let end_point = TP::to_point(&range.end, &snapshot);
 6095                            let start_point = TP::to_point(&range.start, &snapshot);
 6096                            (start_point..end_point, text)
 6097                        })
 6098                        .sorted_by_key(|(range, _)| range.start);
 6099                    buffer.edit(edits, None, cx);
 6100                })
 6101            }
 6102
 6103            editor.refresh_edit_prediction(true, false, window, cx);
 6104        });
 6105        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors_arc(), &snapshot);
 6106
 6107        let show_new_completions_on_confirm = completion
 6108            .confirm
 6109            .as_ref()
 6110            .is_some_and(|confirm| confirm(intent, window, cx));
 6111        if show_new_completions_on_confirm {
 6112            self.open_or_update_completions_menu(None, None, false, window, cx);
 6113        }
 6114
 6115        let provider = self.completion_provider.as_ref()?;
 6116        drop(completion);
 6117        let apply_edits = provider.apply_additional_edits_for_completion(
 6118            buffer_handle,
 6119            completions_menu.completions.clone(),
 6120            candidate_id,
 6121            true,
 6122            cx,
 6123        );
 6124
 6125        let editor_settings = EditorSettings::get_global(cx);
 6126        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 6127            // After the code completion is finished, users often want to know what signatures are needed.
 6128            // so we should automatically call signature_help
 6129            self.show_signature_help(&ShowSignatureHelp, window, cx);
 6130        }
 6131
 6132        Some(cx.foreground_executor().spawn(async move {
 6133            apply_edits.await?;
 6134            Ok(())
 6135        }))
 6136    }
 6137
 6138    pub fn toggle_code_actions(
 6139        &mut self,
 6140        action: &ToggleCodeActions,
 6141        window: &mut Window,
 6142        cx: &mut Context<Self>,
 6143    ) {
 6144        let quick_launch = action.quick_launch;
 6145        let mut context_menu = self.context_menu.borrow_mut();
 6146        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 6147            if code_actions.deployed_from == action.deployed_from {
 6148                // Toggle if we're selecting the same one
 6149                *context_menu = None;
 6150                cx.notify();
 6151                return;
 6152            } else {
 6153                // Otherwise, clear it and start a new one
 6154                *context_menu = None;
 6155                cx.notify();
 6156            }
 6157        }
 6158        drop(context_menu);
 6159        let snapshot = self.snapshot(window, cx);
 6160        let deployed_from = action.deployed_from.clone();
 6161        let action = action.clone();
 6162        self.completion_tasks.clear();
 6163        self.discard_edit_prediction(false, cx);
 6164
 6165        let multibuffer_point = match &action.deployed_from {
 6166            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 6167                DisplayPoint::new(*row, 0).to_point(&snapshot)
 6168            }
 6169            _ => self
 6170                .selections
 6171                .newest::<Point>(&snapshot.display_snapshot)
 6172                .head(),
 6173        };
 6174        let Some((buffer, buffer_row)) = snapshot
 6175            .buffer_snapshot()
 6176            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 6177            .and_then(|(buffer_snapshot, range)| {
 6178                self.buffer()
 6179                    .read(cx)
 6180                    .buffer(buffer_snapshot.remote_id())
 6181                    .map(|buffer| (buffer, range.start.row))
 6182            })
 6183        else {
 6184            return;
 6185        };
 6186        let buffer_id = buffer.read(cx).remote_id();
 6187        let tasks = self
 6188            .tasks
 6189            .get(&(buffer_id, buffer_row))
 6190            .map(|t| Arc::new(t.to_owned()));
 6191
 6192        if !self.focus_handle.is_focused(window) {
 6193            return;
 6194        }
 6195        let project = self.project.clone();
 6196
 6197        let code_actions_task = match deployed_from {
 6198            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 6199            _ => self.code_actions(buffer_row, window, cx),
 6200        };
 6201
 6202        let runnable_task = match deployed_from {
 6203            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 6204            _ => {
 6205                let mut task_context_task = Task::ready(None);
 6206                if let Some(tasks) = &tasks
 6207                    && let Some(project) = project
 6208                {
 6209                    task_context_task =
 6210                        Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx);
 6211                }
 6212
 6213                cx.spawn_in(window, {
 6214                    let buffer = buffer.clone();
 6215                    async move |editor, cx| {
 6216                        let task_context = task_context_task.await;
 6217
 6218                        let resolved_tasks =
 6219                            tasks
 6220                                .zip(task_context.clone())
 6221                                .map(|(tasks, task_context)| ResolvedTasks {
 6222                                    templates: tasks.resolve(&task_context).collect(),
 6223                                    position: snapshot.buffer_snapshot().anchor_before(Point::new(
 6224                                        multibuffer_point.row,
 6225                                        tasks.column,
 6226                                    )),
 6227                                });
 6228                        let debug_scenarios = editor
 6229                            .update(cx, |editor, cx| {
 6230                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 6231                            })?
 6232                            .await;
 6233                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 6234                    }
 6235                })
 6236            }
 6237        };
 6238
 6239        cx.spawn_in(window, async move |editor, cx| {
 6240            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 6241            let code_actions = code_actions_task.await;
 6242            let spawn_straight_away = quick_launch
 6243                && resolved_tasks
 6244                    .as_ref()
 6245                    .is_some_and(|tasks| tasks.templates.len() == 1)
 6246                && code_actions
 6247                    .as_ref()
 6248                    .is_none_or(|actions| actions.is_empty())
 6249                && debug_scenarios.is_empty();
 6250
 6251            editor.update_in(cx, |editor, window, cx| {
 6252                crate::hover_popover::hide_hover(editor, cx);
 6253                let actions = CodeActionContents::new(
 6254                    resolved_tasks,
 6255                    code_actions,
 6256                    debug_scenarios,
 6257                    task_context.unwrap_or_default(),
 6258                );
 6259
 6260                // Don't show the menu if there are no actions available
 6261                if actions.is_empty() {
 6262                    cx.notify();
 6263                    return Task::ready(Ok(()));
 6264                }
 6265
 6266                *editor.context_menu.borrow_mut() =
 6267                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 6268                        buffer,
 6269                        actions,
 6270                        selected_item: Default::default(),
 6271                        scroll_handle: UniformListScrollHandle::default(),
 6272                        deployed_from,
 6273                    }));
 6274                cx.notify();
 6275                if spawn_straight_away
 6276                    && let Some(task) = editor.confirm_code_action(
 6277                        &ConfirmCodeAction { item_ix: Some(0) },
 6278                        window,
 6279                        cx,
 6280                    )
 6281                {
 6282                    return task;
 6283                }
 6284
 6285                Task::ready(Ok(()))
 6286            })
 6287        })
 6288        .detach_and_log_err(cx);
 6289    }
 6290
 6291    fn debug_scenarios(
 6292        &mut self,
 6293        resolved_tasks: &Option<ResolvedTasks>,
 6294        buffer: &Entity<Buffer>,
 6295        cx: &mut App,
 6296    ) -> Task<Vec<task::DebugScenario>> {
 6297        maybe!({
 6298            let project = self.project()?;
 6299            let dap_store = project.read(cx).dap_store();
 6300            let mut scenarios = vec![];
 6301            let resolved_tasks = resolved_tasks.as_ref()?;
 6302            let buffer = buffer.read(cx);
 6303            let language = buffer.language()?;
 6304            let file = buffer.file();
 6305            let debug_adapter = language_settings(language.name().into(), file, cx)
 6306                .debuggers
 6307                .first()
 6308                .map(SharedString::from)
 6309                .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 6310
 6311            dap_store.update(cx, |dap_store, cx| {
 6312                for (_, task) in &resolved_tasks.templates {
 6313                    let maybe_scenario = dap_store.debug_scenario_for_build_task(
 6314                        task.original_task().clone(),
 6315                        debug_adapter.clone().into(),
 6316                        task.display_label().to_owned().into(),
 6317                        cx,
 6318                    );
 6319                    scenarios.push(maybe_scenario);
 6320                }
 6321            });
 6322            Some(cx.background_spawn(async move {
 6323                futures::future::join_all(scenarios)
 6324                    .await
 6325                    .into_iter()
 6326                    .flatten()
 6327                    .collect::<Vec<_>>()
 6328            }))
 6329        })
 6330        .unwrap_or_else(|| Task::ready(vec![]))
 6331    }
 6332
 6333    fn code_actions(
 6334        &mut self,
 6335        buffer_row: u32,
 6336        window: &mut Window,
 6337        cx: &mut Context<Self>,
 6338    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 6339        let mut task = self.code_actions_task.take();
 6340        cx.spawn_in(window, async move |editor, cx| {
 6341            while let Some(prev_task) = task {
 6342                prev_task.await.log_err();
 6343                task = editor
 6344                    .update(cx, |this, _| this.code_actions_task.take())
 6345                    .ok()?;
 6346            }
 6347
 6348            editor
 6349                .update(cx, |editor, cx| {
 6350                    editor
 6351                        .available_code_actions
 6352                        .clone()
 6353                        .and_then(|(location, code_actions)| {
 6354                            let snapshot = location.buffer.read(cx).snapshot();
 6355                            let point_range = location.range.to_point(&snapshot);
 6356                            let point_range = point_range.start.row..=point_range.end.row;
 6357                            if point_range.contains(&buffer_row) {
 6358                                Some(code_actions)
 6359                            } else {
 6360                                None
 6361                            }
 6362                        })
 6363                })
 6364                .ok()
 6365                .flatten()
 6366        })
 6367    }
 6368
 6369    pub fn confirm_code_action(
 6370        &mut self,
 6371        action: &ConfirmCodeAction,
 6372        window: &mut Window,
 6373        cx: &mut Context<Self>,
 6374    ) -> Option<Task<Result<()>>> {
 6375        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6376
 6377        let actions_menu =
 6378            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 6379                menu
 6380            } else {
 6381                return None;
 6382            };
 6383
 6384        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 6385        let action = actions_menu.actions.get(action_ix)?;
 6386        let title = action.label();
 6387        let buffer = actions_menu.buffer;
 6388        let workspace = self.workspace()?;
 6389
 6390        match action {
 6391            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 6392                workspace.update(cx, |workspace, cx| {
 6393                    workspace.schedule_resolved_task(
 6394                        task_source_kind,
 6395                        resolved_task,
 6396                        false,
 6397                        window,
 6398                        cx,
 6399                    );
 6400
 6401                    Some(Task::ready(Ok(())))
 6402                })
 6403            }
 6404            CodeActionsItem::CodeAction {
 6405                excerpt_id,
 6406                action,
 6407                provider,
 6408            } => {
 6409                let apply_code_action =
 6410                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 6411                let workspace = workspace.downgrade();
 6412                Some(cx.spawn_in(window, async move |editor, cx| {
 6413                    let project_transaction = apply_code_action.await?;
 6414                    Self::open_project_transaction(
 6415                        &editor,
 6416                        workspace,
 6417                        project_transaction,
 6418                        title,
 6419                        cx,
 6420                    )
 6421                    .await
 6422                }))
 6423            }
 6424            CodeActionsItem::DebugScenario(scenario) => {
 6425                let context = actions_menu.actions.context;
 6426
 6427                workspace.update(cx, |workspace, cx| {
 6428                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 6429                    workspace.start_debug_session(
 6430                        scenario,
 6431                        context,
 6432                        Some(buffer),
 6433                        None,
 6434                        window,
 6435                        cx,
 6436                    );
 6437                });
 6438                Some(Task::ready(Ok(())))
 6439            }
 6440        }
 6441    }
 6442
 6443    pub async fn open_project_transaction(
 6444        editor: &WeakEntity<Editor>,
 6445        workspace: WeakEntity<Workspace>,
 6446        transaction: ProjectTransaction,
 6447        title: String,
 6448        cx: &mut AsyncWindowContext,
 6449    ) -> Result<()> {
 6450        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 6451        cx.update(|_, cx| {
 6452            entries.sort_unstable_by_key(|(buffer, _)| {
 6453                buffer.read(cx).file().map(|f| f.path().clone())
 6454            });
 6455        })?;
 6456        if entries.is_empty() {
 6457            return Ok(());
 6458        }
 6459
 6460        // If the project transaction's edits are all contained within this editor, then
 6461        // avoid opening a new editor to display them.
 6462
 6463        if let [(buffer, transaction)] = &*entries {
 6464            let excerpt = editor.update(cx, |editor, cx| {
 6465                editor
 6466                    .buffer()
 6467                    .read(cx)
 6468                    .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6469            })?;
 6470            if let Some((_, excerpted_buffer, excerpt_range)) = excerpt
 6471                && excerpted_buffer == *buffer
 6472            {
 6473                let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6474                    let excerpt_range = excerpt_range.to_offset(buffer);
 6475                    buffer
 6476                        .edited_ranges_for_transaction::<usize>(transaction)
 6477                        .all(|range| {
 6478                            excerpt_range.start <= range.start && excerpt_range.end >= range.end
 6479                        })
 6480                })?;
 6481
 6482                if all_edits_within_excerpt {
 6483                    return Ok(());
 6484                }
 6485            }
 6486        }
 6487
 6488        let mut ranges_to_highlight = Vec::new();
 6489        let excerpt_buffer = cx.new(|cx| {
 6490            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6491            for (buffer_handle, transaction) in &entries {
 6492                let edited_ranges = buffer_handle
 6493                    .read(cx)
 6494                    .edited_ranges_for_transaction::<Point>(transaction)
 6495                    .collect::<Vec<_>>();
 6496                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6497                    PathKey::for_buffer(buffer_handle, cx),
 6498                    buffer_handle.clone(),
 6499                    edited_ranges,
 6500                    multibuffer_context_lines(cx),
 6501                    cx,
 6502                );
 6503
 6504                ranges_to_highlight.extend(ranges);
 6505            }
 6506            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6507            multibuffer
 6508        })?;
 6509
 6510        workspace.update_in(cx, |workspace, window, cx| {
 6511            let project = workspace.project().clone();
 6512            let editor =
 6513                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6514            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6515            editor.update(cx, |editor, cx| {
 6516                editor.highlight_background::<Self>(
 6517                    &ranges_to_highlight,
 6518                    |theme| theme.colors().editor_highlighted_line_background,
 6519                    cx,
 6520                );
 6521            });
 6522        })?;
 6523
 6524        Ok(())
 6525    }
 6526
 6527    pub fn clear_code_action_providers(&mut self) {
 6528        self.code_action_providers.clear();
 6529        self.available_code_actions.take();
 6530    }
 6531
 6532    pub fn add_code_action_provider(
 6533        &mut self,
 6534        provider: Rc<dyn CodeActionProvider>,
 6535        window: &mut Window,
 6536        cx: &mut Context<Self>,
 6537    ) {
 6538        if self
 6539            .code_action_providers
 6540            .iter()
 6541            .any(|existing_provider| existing_provider.id() == provider.id())
 6542        {
 6543            return;
 6544        }
 6545
 6546        self.code_action_providers.push(provider);
 6547        self.refresh_code_actions(window, cx);
 6548    }
 6549
 6550    pub fn remove_code_action_provider(
 6551        &mut self,
 6552        id: Arc<str>,
 6553        window: &mut Window,
 6554        cx: &mut Context<Self>,
 6555    ) {
 6556        self.code_action_providers
 6557            .retain(|provider| provider.id() != id);
 6558        self.refresh_code_actions(window, cx);
 6559    }
 6560
 6561    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6562        !self.code_action_providers.is_empty()
 6563            && EditorSettings::get_global(cx).toolbar.code_actions
 6564    }
 6565
 6566    pub fn has_available_code_actions(&self) -> bool {
 6567        self.available_code_actions
 6568            .as_ref()
 6569            .is_some_and(|(_, actions)| !actions.is_empty())
 6570    }
 6571
 6572    fn render_inline_code_actions(
 6573        &self,
 6574        icon_size: ui::IconSize,
 6575        display_row: DisplayRow,
 6576        is_active: bool,
 6577        cx: &mut Context<Self>,
 6578    ) -> AnyElement {
 6579        let show_tooltip = !self.context_menu_visible();
 6580        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6581            .icon_size(icon_size)
 6582            .shape(ui::IconButtonShape::Square)
 6583            .icon_color(ui::Color::Hidden)
 6584            .toggle_state(is_active)
 6585            .when(show_tooltip, |this| {
 6586                this.tooltip({
 6587                    let focus_handle = self.focus_handle.clone();
 6588                    move |_window, cx| {
 6589                        Tooltip::for_action_in(
 6590                            "Toggle Code Actions",
 6591                            &ToggleCodeActions {
 6592                                deployed_from: None,
 6593                                quick_launch: false,
 6594                            },
 6595                            &focus_handle,
 6596                            cx,
 6597                        )
 6598                    }
 6599                })
 6600            })
 6601            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6602                window.focus(&editor.focus_handle(cx));
 6603                editor.toggle_code_actions(
 6604                    &crate::actions::ToggleCodeActions {
 6605                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6606                            display_row,
 6607                        )),
 6608                        quick_launch: false,
 6609                    },
 6610                    window,
 6611                    cx,
 6612                );
 6613            }))
 6614            .into_any_element()
 6615    }
 6616
 6617    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6618        &self.context_menu
 6619    }
 6620
 6621    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6622        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6623            cx.background_executor()
 6624                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6625                .await;
 6626
 6627            let (start_buffer, start, _, end, newest_selection) = this
 6628                .update(cx, |this, cx| {
 6629                    let newest_selection = this.selections.newest_anchor().clone();
 6630                    if newest_selection.head().diff_base_anchor.is_some() {
 6631                        return None;
 6632                    }
 6633                    let display_snapshot = this.display_snapshot(cx);
 6634                    let newest_selection_adjusted =
 6635                        this.selections.newest_adjusted(&display_snapshot);
 6636                    let buffer = this.buffer.read(cx);
 6637
 6638                    let (start_buffer, start) =
 6639                        buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6640                    let (end_buffer, end) =
 6641                        buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6642
 6643                    Some((start_buffer, start, end_buffer, end, newest_selection))
 6644                })?
 6645                .filter(|(start_buffer, _, end_buffer, _, _)| start_buffer == end_buffer)
 6646                .context(
 6647                    "Expected selection to lie in a single buffer when refreshing code actions",
 6648                )?;
 6649            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6650                let providers = this.code_action_providers.clone();
 6651                let tasks = this
 6652                    .code_action_providers
 6653                    .iter()
 6654                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6655                    .collect::<Vec<_>>();
 6656                (providers, tasks)
 6657            })?;
 6658
 6659            let mut actions = Vec::new();
 6660            for (provider, provider_actions) in
 6661                providers.into_iter().zip(future::join_all(tasks).await)
 6662            {
 6663                if let Some(provider_actions) = provider_actions.log_err() {
 6664                    actions.extend(provider_actions.into_iter().map(|action| {
 6665                        AvailableCodeAction {
 6666                            excerpt_id: newest_selection.start.excerpt_id,
 6667                            action,
 6668                            provider: provider.clone(),
 6669                        }
 6670                    }));
 6671                }
 6672            }
 6673
 6674            this.update(cx, |this, cx| {
 6675                this.available_code_actions = if actions.is_empty() {
 6676                    None
 6677                } else {
 6678                    Some((
 6679                        Location {
 6680                            buffer: start_buffer,
 6681                            range: start..end,
 6682                        },
 6683                        actions.into(),
 6684                    ))
 6685                };
 6686                cx.notify();
 6687            })
 6688        }));
 6689    }
 6690
 6691    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6692        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6693            self.show_git_blame_inline = false;
 6694
 6695            self.show_git_blame_inline_delay_task =
 6696                Some(cx.spawn_in(window, async move |this, cx| {
 6697                    cx.background_executor().timer(delay).await;
 6698
 6699                    this.update(cx, |this, cx| {
 6700                        this.show_git_blame_inline = true;
 6701                        cx.notify();
 6702                    })
 6703                    .log_err();
 6704                }));
 6705        }
 6706    }
 6707
 6708    pub fn blame_hover(&mut self, _: &BlameHover, window: &mut Window, cx: &mut Context<Self>) {
 6709        let snapshot = self.snapshot(window, cx);
 6710        let cursor = self
 6711            .selections
 6712            .newest::<Point>(&snapshot.display_snapshot)
 6713            .head();
 6714        let Some((buffer, point, _)) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)
 6715        else {
 6716            return;
 6717        };
 6718
 6719        let Some(blame) = self.blame.as_ref() else {
 6720            return;
 6721        };
 6722
 6723        let row_info = RowInfo {
 6724            buffer_id: Some(buffer.remote_id()),
 6725            buffer_row: Some(point.row),
 6726            ..Default::default()
 6727        };
 6728        let Some((buffer, blame_entry)) = blame
 6729            .update(cx, |blame, cx| blame.blame_for_rows(&[row_info], cx).next())
 6730            .flatten()
 6731        else {
 6732            return;
 6733        };
 6734
 6735        let anchor = self.selections.newest_anchor().head();
 6736        let position = self.to_pixel_point(anchor, &snapshot, window);
 6737        if let (Some(position), Some(last_bounds)) = (position, self.last_bounds) {
 6738            self.show_blame_popover(
 6739                buffer,
 6740                &blame_entry,
 6741                position + last_bounds.origin,
 6742                true,
 6743                cx,
 6744            );
 6745        };
 6746    }
 6747
 6748    fn show_blame_popover(
 6749        &mut self,
 6750        buffer: BufferId,
 6751        blame_entry: &BlameEntry,
 6752        position: gpui::Point<Pixels>,
 6753        ignore_timeout: bool,
 6754        cx: &mut Context<Self>,
 6755    ) {
 6756        if let Some(state) = &mut self.inline_blame_popover {
 6757            state.hide_task.take();
 6758        } else {
 6759            let blame_popover_delay = EditorSettings::get_global(cx).hover_popover_delay.0;
 6760            let blame_entry = blame_entry.clone();
 6761            let show_task = cx.spawn(async move |editor, cx| {
 6762                if !ignore_timeout {
 6763                    cx.background_executor()
 6764                        .timer(std::time::Duration::from_millis(blame_popover_delay))
 6765                        .await;
 6766                }
 6767                editor
 6768                    .update(cx, |editor, cx| {
 6769                        editor.inline_blame_popover_show_task.take();
 6770                        let Some(blame) = editor.blame.as_ref() else {
 6771                            return;
 6772                        };
 6773                        let blame = blame.read(cx);
 6774                        let details = blame.details_for_entry(buffer, &blame_entry);
 6775                        let markdown = cx.new(|cx| {
 6776                            Markdown::new(
 6777                                details
 6778                                    .as_ref()
 6779                                    .map(|message| message.message.clone())
 6780                                    .unwrap_or_default(),
 6781                                None,
 6782                                None,
 6783                                cx,
 6784                            )
 6785                        });
 6786                        editor.inline_blame_popover = Some(InlineBlamePopover {
 6787                            position,
 6788                            hide_task: None,
 6789                            popover_bounds: None,
 6790                            popover_state: InlineBlamePopoverState {
 6791                                scroll_handle: ScrollHandle::new(),
 6792                                commit_message: details,
 6793                                markdown,
 6794                            },
 6795                            keyboard_grace: ignore_timeout,
 6796                        });
 6797                        cx.notify();
 6798                    })
 6799                    .ok();
 6800            });
 6801            self.inline_blame_popover_show_task = Some(show_task);
 6802        }
 6803    }
 6804
 6805    fn hide_blame_popover(&mut self, ignore_timeout: bool, cx: &mut Context<Self>) -> bool {
 6806        self.inline_blame_popover_show_task.take();
 6807        if let Some(state) = &mut self.inline_blame_popover {
 6808            let hide_task = cx.spawn(async move |editor, cx| {
 6809                if !ignore_timeout {
 6810                    cx.background_executor()
 6811                        .timer(std::time::Duration::from_millis(100))
 6812                        .await;
 6813                }
 6814                editor
 6815                    .update(cx, |editor, cx| {
 6816                        editor.inline_blame_popover.take();
 6817                        cx.notify();
 6818                    })
 6819                    .ok();
 6820            });
 6821            state.hide_task = Some(hide_task);
 6822            true
 6823        } else {
 6824            false
 6825        }
 6826    }
 6827
 6828    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 6829        if self.pending_rename.is_some() {
 6830            return None;
 6831        }
 6832
 6833        let provider = self.semantics_provider.clone()?;
 6834        let buffer = self.buffer.read(cx);
 6835        let newest_selection = self.selections.newest_anchor().clone();
 6836        let cursor_position = newest_selection.head();
 6837        let (cursor_buffer, cursor_buffer_position) =
 6838            buffer.text_anchor_for_position(cursor_position, cx)?;
 6839        let (tail_buffer, tail_buffer_position) =
 6840            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 6841        if cursor_buffer != tail_buffer {
 6842            return None;
 6843        }
 6844
 6845        let snapshot = cursor_buffer.read(cx).snapshot();
 6846        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position, None);
 6847        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position, None);
 6848        if start_word_range != end_word_range {
 6849            self.document_highlights_task.take();
 6850            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6851            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6852            return None;
 6853        }
 6854
 6855        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce.0;
 6856        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6857            cx.background_executor()
 6858                .timer(Duration::from_millis(debounce))
 6859                .await;
 6860
 6861            let highlights = if let Some(highlights) = cx
 6862                .update(|cx| {
 6863                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 6864                })
 6865                .ok()
 6866                .flatten()
 6867            {
 6868                highlights.await.log_err()
 6869            } else {
 6870                None
 6871            };
 6872
 6873            if let Some(highlights) = highlights {
 6874                this.update(cx, |this, cx| {
 6875                    if this.pending_rename.is_some() {
 6876                        return;
 6877                    }
 6878
 6879                    let buffer = this.buffer.read(cx);
 6880                    if buffer
 6881                        .text_anchor_for_position(cursor_position, cx)
 6882                        .is_none_or(|(buffer, _)| buffer != cursor_buffer)
 6883                    {
 6884                        return;
 6885                    }
 6886
 6887                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 6888                    let mut write_ranges = Vec::new();
 6889                    let mut read_ranges = Vec::new();
 6890                    for highlight in highlights {
 6891                        let buffer_id = cursor_buffer.read(cx).remote_id();
 6892                        for (excerpt_id, excerpt_range) in buffer.excerpts_for_buffer(buffer_id, cx)
 6893                        {
 6894                            let start = highlight
 6895                                .range
 6896                                .start
 6897                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 6898                            let end = highlight
 6899                                .range
 6900                                .end
 6901                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6902                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6903                                continue;
 6904                            }
 6905
 6906                            let range =
 6907                                Anchor::range_in_buffer(excerpt_id, buffer_id, *start..*end);
 6908                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 6909                                write_ranges.push(range);
 6910                            } else {
 6911                                read_ranges.push(range);
 6912                            }
 6913                        }
 6914                    }
 6915
 6916                    this.highlight_background::<DocumentHighlightRead>(
 6917                        &read_ranges,
 6918                        |theme| theme.colors().editor_document_highlight_read_background,
 6919                        cx,
 6920                    );
 6921                    this.highlight_background::<DocumentHighlightWrite>(
 6922                        &write_ranges,
 6923                        |theme| theme.colors().editor_document_highlight_write_background,
 6924                        cx,
 6925                    );
 6926                    cx.notify();
 6927                })
 6928                .log_err();
 6929            }
 6930        }));
 6931        None
 6932    }
 6933
 6934    fn prepare_highlight_query_from_selection(
 6935        &mut self,
 6936        window: &Window,
 6937        cx: &mut Context<Editor>,
 6938    ) -> Option<(String, Range<Anchor>)> {
 6939        if matches!(self.mode, EditorMode::SingleLine) {
 6940            return None;
 6941        }
 6942        if !EditorSettings::get_global(cx).selection_highlight {
 6943            return None;
 6944        }
 6945        if self.selections.count() != 1 || self.selections.line_mode() {
 6946            return None;
 6947        }
 6948        let snapshot = self.snapshot(window, cx);
 6949        let selection = self.selections.newest::<Point>(&snapshot);
 6950        // If the selection spans multiple rows OR it is empty
 6951        if selection.start.row != selection.end.row
 6952            || selection.start.column == selection.end.column
 6953        {
 6954            return None;
 6955        }
 6956        let selection_anchor_range = selection.range().to_anchors(snapshot.buffer_snapshot());
 6957        let query = snapshot
 6958            .buffer_snapshot()
 6959            .text_for_range(selection_anchor_range.clone())
 6960            .collect::<String>();
 6961        if query.trim().is_empty() {
 6962            return None;
 6963        }
 6964        Some((query, selection_anchor_range))
 6965    }
 6966
 6967    fn update_selection_occurrence_highlights(
 6968        &mut self,
 6969        query_text: String,
 6970        query_range: Range<Anchor>,
 6971        multi_buffer_range_to_query: Range<Point>,
 6972        use_debounce: bool,
 6973        window: &mut Window,
 6974        cx: &mut Context<Editor>,
 6975    ) -> Task<()> {
 6976        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6977        cx.spawn_in(window, async move |editor, cx| {
 6978            if use_debounce {
 6979                cx.background_executor()
 6980                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 6981                    .await;
 6982            }
 6983            let match_task = cx.background_spawn(async move {
 6984                let buffer_ranges = multi_buffer_snapshot
 6985                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 6986                    .into_iter()
 6987                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 6988                let mut match_ranges = Vec::new();
 6989                let Ok(regex) = project::search::SearchQuery::text(
 6990                    query_text.clone(),
 6991                    false,
 6992                    false,
 6993                    false,
 6994                    Default::default(),
 6995                    Default::default(),
 6996                    false,
 6997                    None,
 6998                ) else {
 6999                    return Vec::default();
 7000                };
 7001                let query_range = query_range.to_anchors(&multi_buffer_snapshot);
 7002                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 7003                    match_ranges.extend(
 7004                        regex
 7005                            .search(buffer_snapshot, Some(search_range.clone()))
 7006                            .await
 7007                            .into_iter()
 7008                            .filter_map(|match_range| {
 7009                                let match_start = buffer_snapshot
 7010                                    .anchor_after(search_range.start + match_range.start);
 7011                                let match_end = buffer_snapshot
 7012                                    .anchor_before(search_range.start + match_range.end);
 7013                                let match_anchor_range = Anchor::range_in_buffer(
 7014                                    excerpt_id,
 7015                                    buffer_snapshot.remote_id(),
 7016                                    match_start..match_end,
 7017                                );
 7018                                (match_anchor_range != query_range).then_some(match_anchor_range)
 7019                            }),
 7020                    );
 7021                }
 7022                match_ranges
 7023            });
 7024            let match_ranges = match_task.await;
 7025            editor
 7026                .update_in(cx, |editor, _, cx| {
 7027                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 7028                    if !match_ranges.is_empty() {
 7029                        editor.highlight_background::<SelectedTextHighlight>(
 7030                            &match_ranges,
 7031                            |theme| theme.colors().editor_document_highlight_bracket_background,
 7032                            cx,
 7033                        )
 7034                    }
 7035                })
 7036                .log_err();
 7037        })
 7038    }
 7039
 7040    fn refresh_single_line_folds(&mut self, window: &mut Window, cx: &mut Context<Editor>) {
 7041        struct NewlineFold;
 7042        let type_id = std::any::TypeId::of::<NewlineFold>();
 7043        if !self.mode.is_single_line() {
 7044            return;
 7045        }
 7046        let snapshot = self.snapshot(window, cx);
 7047        if snapshot.buffer_snapshot().max_point().row == 0 {
 7048            return;
 7049        }
 7050        let task = cx.background_spawn(async move {
 7051            let new_newlines = snapshot
 7052                .buffer_chars_at(0)
 7053                .filter_map(|(c, i)| {
 7054                    if c == '\n' {
 7055                        Some(
 7056                            snapshot.buffer_snapshot().anchor_after(i)
 7057                                ..snapshot.buffer_snapshot().anchor_before(i + 1),
 7058                        )
 7059                    } else {
 7060                        None
 7061                    }
 7062                })
 7063                .collect::<Vec<_>>();
 7064            let existing_newlines = snapshot
 7065                .folds_in_range(0..snapshot.buffer_snapshot().len())
 7066                .filter_map(|fold| {
 7067                    if fold.placeholder.type_tag == Some(type_id) {
 7068                        Some(fold.range.start..fold.range.end)
 7069                    } else {
 7070                        None
 7071                    }
 7072                })
 7073                .collect::<Vec<_>>();
 7074
 7075            (new_newlines, existing_newlines)
 7076        });
 7077        self.folding_newlines = cx.spawn(async move |this, cx| {
 7078            let (new_newlines, existing_newlines) = task.await;
 7079            if new_newlines == existing_newlines {
 7080                return;
 7081            }
 7082            let placeholder = FoldPlaceholder {
 7083                render: Arc::new(move |_, _, cx| {
 7084                    div()
 7085                        .bg(cx.theme().status().hint_background)
 7086                        .border_b_1()
 7087                        .size_full()
 7088                        .font(ThemeSettings::get_global(cx).buffer_font.clone())
 7089                        .border_color(cx.theme().status().hint)
 7090                        .child("\\n")
 7091                        .into_any()
 7092                }),
 7093                constrain_width: false,
 7094                merge_adjacent: false,
 7095                type_tag: Some(type_id),
 7096            };
 7097            let creases = new_newlines
 7098                .into_iter()
 7099                .map(|range| Crease::simple(range, placeholder.clone()))
 7100                .collect();
 7101            this.update(cx, |this, cx| {
 7102                this.display_map.update(cx, |display_map, cx| {
 7103                    display_map.remove_folds_with_type(existing_newlines, type_id, cx);
 7104                    display_map.fold(creases, cx);
 7105                });
 7106            })
 7107            .ok();
 7108        });
 7109    }
 7110
 7111    fn refresh_selected_text_highlights(
 7112        &mut self,
 7113        on_buffer_edit: bool,
 7114        window: &mut Window,
 7115        cx: &mut Context<Editor>,
 7116    ) {
 7117        let Some((query_text, query_range)) =
 7118            self.prepare_highlight_query_from_selection(window, cx)
 7119        else {
 7120            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 7121            self.quick_selection_highlight_task.take();
 7122            self.debounced_selection_highlight_task.take();
 7123            return;
 7124        };
 7125        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 7126        if on_buffer_edit
 7127            || self
 7128                .quick_selection_highlight_task
 7129                .as_ref()
 7130                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7131        {
 7132            let multi_buffer_visible_start = self
 7133                .scroll_manager
 7134                .anchor()
 7135                .anchor
 7136                .to_point(&multi_buffer_snapshot);
 7137            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 7138                multi_buffer_visible_start
 7139                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 7140                Bias::Left,
 7141            );
 7142            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 7143            self.quick_selection_highlight_task = Some((
 7144                query_range.clone(),
 7145                self.update_selection_occurrence_highlights(
 7146                    query_text.clone(),
 7147                    query_range.clone(),
 7148                    multi_buffer_visible_range,
 7149                    false,
 7150                    window,
 7151                    cx,
 7152                ),
 7153            ));
 7154        }
 7155        if on_buffer_edit
 7156            || self
 7157                .debounced_selection_highlight_task
 7158                .as_ref()
 7159                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7160        {
 7161            let multi_buffer_start = multi_buffer_snapshot
 7162                .anchor_before(0)
 7163                .to_point(&multi_buffer_snapshot);
 7164            let multi_buffer_end = multi_buffer_snapshot
 7165                .anchor_after(multi_buffer_snapshot.len())
 7166                .to_point(&multi_buffer_snapshot);
 7167            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 7168            self.debounced_selection_highlight_task = Some((
 7169                query_range.clone(),
 7170                self.update_selection_occurrence_highlights(
 7171                    query_text,
 7172                    query_range,
 7173                    multi_buffer_full_range,
 7174                    true,
 7175                    window,
 7176                    cx,
 7177                ),
 7178            ));
 7179        }
 7180    }
 7181
 7182    pub fn refresh_edit_prediction(
 7183        &mut self,
 7184        debounce: bool,
 7185        user_requested: bool,
 7186        window: &mut Window,
 7187        cx: &mut Context<Self>,
 7188    ) -> Option<()> {
 7189        if DisableAiSettings::get_global(cx).disable_ai {
 7190            return None;
 7191        }
 7192
 7193        let provider = self.edit_prediction_provider()?;
 7194        let cursor = self.selections.newest_anchor().head();
 7195        let (buffer, cursor_buffer_position) =
 7196            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7197
 7198        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 7199            self.discard_edit_prediction(false, cx);
 7200            return None;
 7201        }
 7202
 7203        self.update_visible_edit_prediction(window, cx);
 7204
 7205        if !user_requested
 7206            && (!self.should_show_edit_predictions()
 7207                || !self.is_focused(window)
 7208                || buffer.read(cx).is_empty())
 7209        {
 7210            self.discard_edit_prediction(false, cx);
 7211            return None;
 7212        }
 7213
 7214        provider.refresh(buffer, cursor_buffer_position, debounce, cx);
 7215        Some(())
 7216    }
 7217
 7218    fn show_edit_predictions_in_menu(&self) -> bool {
 7219        match self.edit_prediction_settings {
 7220            EditPredictionSettings::Disabled => false,
 7221            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 7222        }
 7223    }
 7224
 7225    pub fn edit_predictions_enabled(&self) -> bool {
 7226        match self.edit_prediction_settings {
 7227            EditPredictionSettings::Disabled => false,
 7228            EditPredictionSettings::Enabled { .. } => true,
 7229        }
 7230    }
 7231
 7232    fn edit_prediction_requires_modifier(&self) -> bool {
 7233        match self.edit_prediction_settings {
 7234            EditPredictionSettings::Disabled => false,
 7235            EditPredictionSettings::Enabled {
 7236                preview_requires_modifier,
 7237                ..
 7238            } => preview_requires_modifier,
 7239        }
 7240    }
 7241
 7242    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 7243        if self.edit_prediction_provider.is_none() || DisableAiSettings::get_global(cx).disable_ai {
 7244            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7245            self.discard_edit_prediction(false, cx);
 7246        } else {
 7247            let selection = self.selections.newest_anchor();
 7248            let cursor = selection.head();
 7249
 7250            if let Some((buffer, cursor_buffer_position)) =
 7251                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7252            {
 7253                self.edit_prediction_settings =
 7254                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7255            }
 7256        }
 7257    }
 7258
 7259    fn edit_prediction_settings_at_position(
 7260        &self,
 7261        buffer: &Entity<Buffer>,
 7262        buffer_position: language::Anchor,
 7263        cx: &App,
 7264    ) -> EditPredictionSettings {
 7265        if !self.mode.is_full()
 7266            || !self.show_edit_predictions_override.unwrap_or(true)
 7267            || self.edit_predictions_disabled_in_scope(buffer, buffer_position, cx)
 7268        {
 7269            return EditPredictionSettings::Disabled;
 7270        }
 7271
 7272        let buffer = buffer.read(cx);
 7273
 7274        let file = buffer.file();
 7275
 7276        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 7277            return EditPredictionSettings::Disabled;
 7278        };
 7279
 7280        let by_provider = matches!(
 7281            self.menu_edit_predictions_policy,
 7282            MenuEditPredictionsPolicy::ByProvider
 7283        );
 7284
 7285        let show_in_menu = by_provider
 7286            && self
 7287                .edit_prediction_provider
 7288                .as_ref()
 7289                .is_some_and(|provider| provider.provider.show_completions_in_menu());
 7290
 7291        let preview_requires_modifier =
 7292            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 7293
 7294        EditPredictionSettings::Enabled {
 7295            show_in_menu,
 7296            preview_requires_modifier,
 7297        }
 7298    }
 7299
 7300    fn should_show_edit_predictions(&self) -> bool {
 7301        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 7302    }
 7303
 7304    pub fn edit_prediction_preview_is_active(&self) -> bool {
 7305        matches!(
 7306            self.edit_prediction_preview,
 7307            EditPredictionPreview::Active { .. }
 7308        )
 7309    }
 7310
 7311    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 7312        let cursor = self.selections.newest_anchor().head();
 7313        if let Some((buffer, cursor_position)) =
 7314            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7315        {
 7316            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 7317        } else {
 7318            false
 7319        }
 7320    }
 7321
 7322    pub fn supports_minimap(&self, cx: &App) -> bool {
 7323        !self.minimap_visibility.disabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton
 7324    }
 7325
 7326    fn edit_predictions_enabled_in_buffer(
 7327        &self,
 7328        buffer: &Entity<Buffer>,
 7329        buffer_position: language::Anchor,
 7330        cx: &App,
 7331    ) -> bool {
 7332        maybe!({
 7333            if self.read_only(cx) {
 7334                return Some(false);
 7335            }
 7336            let provider = self.edit_prediction_provider()?;
 7337            if !provider.is_enabled(buffer, buffer_position, cx) {
 7338                return Some(false);
 7339            }
 7340            let buffer = buffer.read(cx);
 7341            let Some(file) = buffer.file() else {
 7342                return Some(true);
 7343            };
 7344            let settings = all_language_settings(Some(file), cx);
 7345            Some(settings.edit_predictions_enabled_for_file(file, cx))
 7346        })
 7347        .unwrap_or(false)
 7348    }
 7349
 7350    fn cycle_edit_prediction(
 7351        &mut self,
 7352        direction: Direction,
 7353        window: &mut Window,
 7354        cx: &mut Context<Self>,
 7355    ) -> Option<()> {
 7356        let provider = self.edit_prediction_provider()?;
 7357        let cursor = self.selections.newest_anchor().head();
 7358        let (buffer, cursor_buffer_position) =
 7359            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7360        if self.edit_predictions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 7361            return None;
 7362        }
 7363
 7364        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 7365        self.update_visible_edit_prediction(window, cx);
 7366
 7367        Some(())
 7368    }
 7369
 7370    pub fn show_edit_prediction(
 7371        &mut self,
 7372        _: &ShowEditPrediction,
 7373        window: &mut Window,
 7374        cx: &mut Context<Self>,
 7375    ) {
 7376        if !self.has_active_edit_prediction() {
 7377            self.refresh_edit_prediction(false, true, window, cx);
 7378            return;
 7379        }
 7380
 7381        self.update_visible_edit_prediction(window, cx);
 7382    }
 7383
 7384    pub fn display_cursor_names(
 7385        &mut self,
 7386        _: &DisplayCursorNames,
 7387        window: &mut Window,
 7388        cx: &mut Context<Self>,
 7389    ) {
 7390        self.show_cursor_names(window, cx);
 7391    }
 7392
 7393    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7394        self.show_cursor_names = true;
 7395        cx.notify();
 7396        cx.spawn_in(window, async move |this, cx| {
 7397            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 7398            this.update(cx, |this, cx| {
 7399                this.show_cursor_names = false;
 7400                cx.notify()
 7401            })
 7402            .ok()
 7403        })
 7404        .detach();
 7405    }
 7406
 7407    pub fn next_edit_prediction(
 7408        &mut self,
 7409        _: &NextEditPrediction,
 7410        window: &mut Window,
 7411        cx: &mut Context<Self>,
 7412    ) {
 7413        if self.has_active_edit_prediction() {
 7414            self.cycle_edit_prediction(Direction::Next, window, cx);
 7415        } else {
 7416            let is_copilot_disabled = self
 7417                .refresh_edit_prediction(false, true, window, cx)
 7418                .is_none();
 7419            if is_copilot_disabled {
 7420                cx.propagate();
 7421            }
 7422        }
 7423    }
 7424
 7425    pub fn previous_edit_prediction(
 7426        &mut self,
 7427        _: &PreviousEditPrediction,
 7428        window: &mut Window,
 7429        cx: &mut Context<Self>,
 7430    ) {
 7431        if self.has_active_edit_prediction() {
 7432            self.cycle_edit_prediction(Direction::Prev, window, cx);
 7433        } else {
 7434            let is_copilot_disabled = self
 7435                .refresh_edit_prediction(false, true, window, cx)
 7436                .is_none();
 7437            if is_copilot_disabled {
 7438                cx.propagate();
 7439            }
 7440        }
 7441    }
 7442
 7443    pub fn accept_edit_prediction(
 7444        &mut self,
 7445        _: &AcceptEditPrediction,
 7446        window: &mut Window,
 7447        cx: &mut Context<Self>,
 7448    ) {
 7449        if self.show_edit_predictions_in_menu() {
 7450            self.hide_context_menu(window, cx);
 7451        }
 7452
 7453        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7454            return;
 7455        };
 7456
 7457        match &active_edit_prediction.completion {
 7458            EditPrediction::MoveWithin { target, .. } => {
 7459                let target = *target;
 7460
 7461                if let Some(position_map) = &self.last_position_map {
 7462                    if position_map
 7463                        .visible_row_range
 7464                        .contains(&target.to_display_point(&position_map.snapshot).row())
 7465                        || !self.edit_prediction_requires_modifier()
 7466                    {
 7467                        self.unfold_ranges(&[target..target], true, false, cx);
 7468                        // Note that this is also done in vim's handler of the Tab action.
 7469                        self.change_selections(
 7470                            SelectionEffects::scroll(Autoscroll::newest()),
 7471                            window,
 7472                            cx,
 7473                            |selections| {
 7474                                selections.select_anchor_ranges([target..target]);
 7475                            },
 7476                        );
 7477                        self.clear_row_highlights::<EditPredictionPreview>();
 7478
 7479                        self.edit_prediction_preview
 7480                            .set_previous_scroll_position(None);
 7481                    } else {
 7482                        self.edit_prediction_preview
 7483                            .set_previous_scroll_position(Some(
 7484                                position_map.snapshot.scroll_anchor,
 7485                            ));
 7486
 7487                        self.highlight_rows::<EditPredictionPreview>(
 7488                            target..target,
 7489                            cx.theme().colors().editor_highlighted_line_background,
 7490                            RowHighlightOptions {
 7491                                autoscroll: true,
 7492                                ..Default::default()
 7493                            },
 7494                            cx,
 7495                        );
 7496                        self.request_autoscroll(Autoscroll::fit(), cx);
 7497                    }
 7498                }
 7499            }
 7500            EditPrediction::MoveOutside { snapshot, target } => {
 7501                if let Some(workspace) = self.workspace() {
 7502                    Self::open_editor_at_anchor(snapshot, *target, &workspace, window, cx)
 7503                        .detach_and_log_err(cx);
 7504                }
 7505            }
 7506            EditPrediction::Edit { edits, .. } => {
 7507                self.report_edit_prediction_event(
 7508                    active_edit_prediction.completion_id.clone(),
 7509                    true,
 7510                    cx,
 7511                );
 7512
 7513                if let Some(provider) = self.edit_prediction_provider() {
 7514                    provider.accept(cx);
 7515                }
 7516
 7517                // Store the transaction ID and selections before applying the edit
 7518                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 7519
 7520                let snapshot = self.buffer.read(cx).snapshot(cx);
 7521                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 7522
 7523                self.buffer.update(cx, |buffer, cx| {
 7524                    buffer.edit(edits.iter().cloned(), None, cx)
 7525                });
 7526
 7527                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 7528                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 7529                });
 7530
 7531                let selections = self.selections.disjoint_anchors_arc();
 7532                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 7533                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 7534                    if has_new_transaction {
 7535                        self.selection_history
 7536                            .insert_transaction(transaction_id_now, selections);
 7537                    }
 7538                }
 7539
 7540                self.update_visible_edit_prediction(window, cx);
 7541                if self.active_edit_prediction.is_none() {
 7542                    self.refresh_edit_prediction(true, true, window, cx);
 7543                }
 7544
 7545                cx.notify();
 7546            }
 7547        }
 7548
 7549        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 7550    }
 7551
 7552    pub fn accept_partial_edit_prediction(
 7553        &mut self,
 7554        _: &AcceptPartialEditPrediction,
 7555        window: &mut Window,
 7556        cx: &mut Context<Self>,
 7557    ) {
 7558        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7559            return;
 7560        };
 7561        if self.selections.count() != 1 {
 7562            return;
 7563        }
 7564
 7565        match &active_edit_prediction.completion {
 7566            EditPrediction::MoveWithin { target, .. } => {
 7567                let target = *target;
 7568                self.change_selections(
 7569                    SelectionEffects::scroll(Autoscroll::newest()),
 7570                    window,
 7571                    cx,
 7572                    |selections| {
 7573                        selections.select_anchor_ranges([target..target]);
 7574                    },
 7575                );
 7576            }
 7577            EditPrediction::MoveOutside { snapshot, target } => {
 7578                if let Some(workspace) = self.workspace() {
 7579                    Self::open_editor_at_anchor(snapshot, *target, &workspace, window, cx)
 7580                        .detach_and_log_err(cx);
 7581                }
 7582            }
 7583            EditPrediction::Edit { edits, .. } => {
 7584                self.report_edit_prediction_event(
 7585                    active_edit_prediction.completion_id.clone(),
 7586                    true,
 7587                    cx,
 7588                );
 7589
 7590                // Find an insertion that starts at the cursor position.
 7591                let snapshot = self.buffer.read(cx).snapshot(cx);
 7592                let cursor_offset = self
 7593                    .selections
 7594                    .newest::<usize>(&self.display_snapshot(cx))
 7595                    .head();
 7596                let insertion = edits.iter().find_map(|(range, text)| {
 7597                    let range = range.to_offset(&snapshot);
 7598                    if range.is_empty() && range.start == cursor_offset {
 7599                        Some(text)
 7600                    } else {
 7601                        None
 7602                    }
 7603                });
 7604
 7605                if let Some(text) = insertion {
 7606                    let mut partial_completion = text
 7607                        .chars()
 7608                        .by_ref()
 7609                        .take_while(|c| c.is_alphabetic())
 7610                        .collect::<String>();
 7611                    if partial_completion.is_empty() {
 7612                        partial_completion = text
 7613                            .chars()
 7614                            .by_ref()
 7615                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7616                            .collect::<String>();
 7617                    }
 7618
 7619                    cx.emit(EditorEvent::InputHandled {
 7620                        utf16_range_to_replace: None,
 7621                        text: partial_completion.clone().into(),
 7622                    });
 7623
 7624                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 7625
 7626                    self.refresh_edit_prediction(true, true, window, cx);
 7627                    cx.notify();
 7628                } else {
 7629                    self.accept_edit_prediction(&Default::default(), window, cx);
 7630                }
 7631            }
 7632        }
 7633    }
 7634
 7635    fn discard_edit_prediction(
 7636        &mut self,
 7637        should_report_edit_prediction_event: bool,
 7638        cx: &mut Context<Self>,
 7639    ) -> bool {
 7640        if should_report_edit_prediction_event {
 7641            let completion_id = self
 7642                .active_edit_prediction
 7643                .as_ref()
 7644                .and_then(|active_completion| active_completion.completion_id.clone());
 7645
 7646            self.report_edit_prediction_event(completion_id, false, cx);
 7647        }
 7648
 7649        if let Some(provider) = self.edit_prediction_provider() {
 7650            provider.discard(cx);
 7651        }
 7652
 7653        self.take_active_edit_prediction(cx)
 7654    }
 7655
 7656    fn report_edit_prediction_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7657        let Some(provider) = self.edit_prediction_provider() else {
 7658            return;
 7659        };
 7660
 7661        let Some((_, buffer, _)) = self
 7662            .buffer
 7663            .read(cx)
 7664            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7665        else {
 7666            return;
 7667        };
 7668
 7669        let extension = buffer
 7670            .read(cx)
 7671            .file()
 7672            .and_then(|file| Some(file.path().extension()?.to_string()));
 7673
 7674        let event_type = match accepted {
 7675            true => "Edit Prediction Accepted",
 7676            false => "Edit Prediction Discarded",
 7677        };
 7678        telemetry::event!(
 7679            event_type,
 7680            provider = provider.name(),
 7681            prediction_id = id,
 7682            suggestion_accepted = accepted,
 7683            file_extension = extension,
 7684        );
 7685    }
 7686
 7687    fn open_editor_at_anchor(
 7688        snapshot: &language::BufferSnapshot,
 7689        target: language::Anchor,
 7690        workspace: &Entity<Workspace>,
 7691        window: &mut Window,
 7692        cx: &mut App,
 7693    ) -> Task<Result<()>> {
 7694        workspace.update(cx, |workspace, cx| {
 7695            let path = snapshot.file().map(|file| file.full_path(cx));
 7696            let Some(path) =
 7697                path.and_then(|path| workspace.project().read(cx).find_project_path(path, cx))
 7698            else {
 7699                return Task::ready(Err(anyhow::anyhow!("Project path not found")));
 7700            };
 7701            let target = text::ToPoint::to_point(&target, snapshot);
 7702            let item = workspace.open_path(path, None, true, window, cx);
 7703            window.spawn(cx, async move |cx| {
 7704                let Some(editor) = item.await?.downcast::<Editor>() else {
 7705                    return Ok(());
 7706                };
 7707                editor
 7708                    .update_in(cx, |editor, window, cx| {
 7709                        editor.go_to_singleton_buffer_point(target, window, cx);
 7710                    })
 7711                    .ok();
 7712                anyhow::Ok(())
 7713            })
 7714        })
 7715    }
 7716
 7717    pub fn has_active_edit_prediction(&self) -> bool {
 7718        self.active_edit_prediction.is_some()
 7719    }
 7720
 7721    fn take_active_edit_prediction(&mut self, cx: &mut Context<Self>) -> bool {
 7722        let Some(active_edit_prediction) = self.active_edit_prediction.take() else {
 7723            return false;
 7724        };
 7725
 7726        self.splice_inlays(&active_edit_prediction.inlay_ids, Default::default(), cx);
 7727        self.clear_highlights::<EditPredictionHighlight>(cx);
 7728        self.stale_edit_prediction_in_menu = Some(active_edit_prediction);
 7729        true
 7730    }
 7731
 7732    /// Returns true when we're displaying the edit prediction popover below the cursor
 7733    /// like we are not previewing and the LSP autocomplete menu is visible
 7734    /// or we are in `when_holding_modifier` mode.
 7735    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7736        if self.edit_prediction_preview_is_active()
 7737            || !self.show_edit_predictions_in_menu()
 7738            || !self.edit_predictions_enabled()
 7739        {
 7740            return false;
 7741        }
 7742
 7743        if self.has_visible_completions_menu() {
 7744            return true;
 7745        }
 7746
 7747        has_completion && self.edit_prediction_requires_modifier()
 7748    }
 7749
 7750    fn handle_modifiers_changed(
 7751        &mut self,
 7752        modifiers: Modifiers,
 7753        position_map: &PositionMap,
 7754        window: &mut Window,
 7755        cx: &mut Context<Self>,
 7756    ) {
 7757        // Ensure that the edit prediction preview is updated, even when not
 7758        // enabled, if there's an active edit prediction preview.
 7759        if self.show_edit_predictions_in_menu()
 7760            || matches!(
 7761                self.edit_prediction_preview,
 7762                EditPredictionPreview::Active { .. }
 7763            )
 7764        {
 7765            self.update_edit_prediction_preview(&modifiers, window, cx);
 7766        }
 7767
 7768        self.update_selection_mode(&modifiers, position_map, window, cx);
 7769
 7770        let mouse_position = window.mouse_position();
 7771        if !position_map.text_hitbox.is_hovered(window) {
 7772            return;
 7773        }
 7774
 7775        self.update_hovered_link(
 7776            position_map.point_for_position(mouse_position),
 7777            &position_map.snapshot,
 7778            modifiers,
 7779            window,
 7780            cx,
 7781        )
 7782    }
 7783
 7784    fn is_cmd_or_ctrl_pressed(modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7785        match EditorSettings::get_global(cx).multi_cursor_modifier {
 7786            MultiCursorModifier::Alt => modifiers.secondary(),
 7787            MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 7788        }
 7789    }
 7790
 7791    fn is_alt_pressed(modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7792        match EditorSettings::get_global(cx).multi_cursor_modifier {
 7793            MultiCursorModifier::Alt => modifiers.alt,
 7794            MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 7795        }
 7796    }
 7797
 7798    fn columnar_selection_mode(
 7799        modifiers: &Modifiers,
 7800        cx: &mut Context<Self>,
 7801    ) -> Option<ColumnarMode> {
 7802        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 7803            if Self::is_cmd_or_ctrl_pressed(modifiers, cx) {
 7804                Some(ColumnarMode::FromMouse)
 7805            } else if Self::is_alt_pressed(modifiers, cx) {
 7806                Some(ColumnarMode::FromSelection)
 7807            } else {
 7808                None
 7809            }
 7810        } else {
 7811            None
 7812        }
 7813    }
 7814
 7815    fn update_selection_mode(
 7816        &mut self,
 7817        modifiers: &Modifiers,
 7818        position_map: &PositionMap,
 7819        window: &mut Window,
 7820        cx: &mut Context<Self>,
 7821    ) {
 7822        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 7823            return;
 7824        };
 7825        if self.selections.pending_anchor().is_none() {
 7826            return;
 7827        }
 7828
 7829        let mouse_position = window.mouse_position();
 7830        let point_for_position = position_map.point_for_position(mouse_position);
 7831        let position = point_for_position.previous_valid;
 7832
 7833        self.select(
 7834            SelectPhase::BeginColumnar {
 7835                position,
 7836                reset: false,
 7837                mode,
 7838                goal_column: point_for_position.exact_unclipped.column(),
 7839            },
 7840            window,
 7841            cx,
 7842        );
 7843    }
 7844
 7845    fn update_edit_prediction_preview(
 7846        &mut self,
 7847        modifiers: &Modifiers,
 7848        window: &mut Window,
 7849        cx: &mut Context<Self>,
 7850    ) {
 7851        let mut modifiers_held = false;
 7852        if let Some(accept_keystroke) = self
 7853            .accept_edit_prediction_keybind(false, window, cx)
 7854            .keystroke()
 7855        {
 7856            modifiers_held = modifiers_held
 7857                || (accept_keystroke.modifiers() == modifiers
 7858                    && accept_keystroke.modifiers().modified());
 7859        };
 7860        if let Some(accept_partial_keystroke) = self
 7861            .accept_edit_prediction_keybind(true, window, cx)
 7862            .keystroke()
 7863        {
 7864            modifiers_held = modifiers_held
 7865                || (accept_partial_keystroke.modifiers() == modifiers
 7866                    && accept_partial_keystroke.modifiers().modified());
 7867        }
 7868
 7869        if modifiers_held {
 7870            if matches!(
 7871                self.edit_prediction_preview,
 7872                EditPredictionPreview::Inactive { .. }
 7873            ) {
 7874                self.edit_prediction_preview = EditPredictionPreview::Active {
 7875                    previous_scroll_position: None,
 7876                    since: Instant::now(),
 7877                };
 7878
 7879                self.update_visible_edit_prediction(window, cx);
 7880                cx.notify();
 7881            }
 7882        } else if let EditPredictionPreview::Active {
 7883            previous_scroll_position,
 7884            since,
 7885        } = self.edit_prediction_preview
 7886        {
 7887            if let (Some(previous_scroll_position), Some(position_map)) =
 7888                (previous_scroll_position, self.last_position_map.as_ref())
 7889            {
 7890                self.set_scroll_position(
 7891                    previous_scroll_position
 7892                        .scroll_position(&position_map.snapshot.display_snapshot),
 7893                    window,
 7894                    cx,
 7895                );
 7896            }
 7897
 7898            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 7899                released_too_fast: since.elapsed() < Duration::from_millis(200),
 7900            };
 7901            self.clear_row_highlights::<EditPredictionPreview>();
 7902            self.update_visible_edit_prediction(window, cx);
 7903            cx.notify();
 7904        }
 7905    }
 7906
 7907    fn update_visible_edit_prediction(
 7908        &mut self,
 7909        _window: &mut Window,
 7910        cx: &mut Context<Self>,
 7911    ) -> Option<()> {
 7912        if DisableAiSettings::get_global(cx).disable_ai {
 7913            return None;
 7914        }
 7915
 7916        if self.ime_transaction.is_some() {
 7917            self.discard_edit_prediction(false, cx);
 7918            return None;
 7919        }
 7920
 7921        let selection = self.selections.newest_anchor();
 7922        let cursor = selection.head();
 7923        let multibuffer = self.buffer.read(cx).snapshot(cx);
 7924        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 7925        let excerpt_id = cursor.excerpt_id;
 7926
 7927        let show_in_menu = self.show_edit_predictions_in_menu();
 7928        let completions_menu_has_precedence = !show_in_menu
 7929            && (self.context_menu.borrow().is_some()
 7930                || (!self.completion_tasks.is_empty() && !self.has_active_edit_prediction()));
 7931
 7932        if completions_menu_has_precedence
 7933            || !offset_selection.is_empty()
 7934            || self
 7935                .active_edit_prediction
 7936                .as_ref()
 7937                .is_some_and(|completion| {
 7938                    let Some(invalidation_range) = completion.invalidation_range.as_ref() else {
 7939                        return false;
 7940                    };
 7941                    let invalidation_range = invalidation_range.to_offset(&multibuffer);
 7942                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 7943                    !invalidation_range.contains(&offset_selection.head())
 7944                })
 7945        {
 7946            self.discard_edit_prediction(false, cx);
 7947            return None;
 7948        }
 7949
 7950        self.take_active_edit_prediction(cx);
 7951        let Some(provider) = self.edit_prediction_provider() else {
 7952            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7953            return None;
 7954        };
 7955
 7956        let (buffer, cursor_buffer_position) =
 7957            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7958
 7959        self.edit_prediction_settings =
 7960            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7961
 7962        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 7963
 7964        if self.edit_prediction_indent_conflict {
 7965            let cursor_point = cursor.to_point(&multibuffer);
 7966
 7967            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 7968
 7969            if let Some((_, indent)) = indents.iter().next()
 7970                && indent.len == cursor_point.column
 7971            {
 7972                self.edit_prediction_indent_conflict = false;
 7973            }
 7974        }
 7975
 7976        let edit_prediction = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 7977
 7978        let (completion_id, edits, edit_preview) = match edit_prediction {
 7979            edit_prediction::EditPrediction::Local {
 7980                id,
 7981                edits,
 7982                edit_preview,
 7983            } => (id, edits, edit_preview),
 7984            edit_prediction::EditPrediction::Jump {
 7985                id,
 7986                snapshot,
 7987                target,
 7988            } => {
 7989                self.stale_edit_prediction_in_menu = None;
 7990                self.active_edit_prediction = Some(EditPredictionState {
 7991                    inlay_ids: vec![],
 7992                    completion: EditPrediction::MoveOutside { snapshot, target },
 7993                    completion_id: id,
 7994                    invalidation_range: None,
 7995                });
 7996                cx.notify();
 7997                return Some(());
 7998            }
 7999        };
 8000
 8001        let edits = edits
 8002            .into_iter()
 8003            .flat_map(|(range, new_text)| {
 8004                Some((
 8005                    multibuffer.anchor_range_in_excerpt(excerpt_id, range)?,
 8006                    new_text,
 8007                ))
 8008            })
 8009            .collect::<Vec<_>>();
 8010        if edits.is_empty() {
 8011            return None;
 8012        }
 8013
 8014        let first_edit_start = edits.first().unwrap().0.start;
 8015        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 8016        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 8017
 8018        let last_edit_end = edits.last().unwrap().0.end;
 8019        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 8020        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 8021
 8022        let cursor_row = cursor.to_point(&multibuffer).row;
 8023
 8024        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 8025
 8026        let mut inlay_ids = Vec::new();
 8027        let invalidation_row_range;
 8028        let move_invalidation_row_range = if cursor_row < edit_start_row {
 8029            Some(cursor_row..edit_end_row)
 8030        } else if cursor_row > edit_end_row {
 8031            Some(edit_start_row..cursor_row)
 8032        } else {
 8033            None
 8034        };
 8035        let supports_jump = self
 8036            .edit_prediction_provider
 8037            .as_ref()
 8038            .map(|provider| provider.provider.supports_jump_to_edit())
 8039            .unwrap_or(true);
 8040
 8041        let is_move = supports_jump
 8042            && (move_invalidation_row_range.is_some() || self.edit_predictions_hidden_for_vim_mode);
 8043        let completion = if is_move {
 8044            invalidation_row_range =
 8045                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 8046            let target = first_edit_start;
 8047            EditPrediction::MoveWithin { target, snapshot }
 8048        } else {
 8049            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 8050                && !self.edit_predictions_hidden_for_vim_mode;
 8051
 8052            if show_completions_in_buffer {
 8053                if edits
 8054                    .iter()
 8055                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 8056                {
 8057                    let mut inlays = Vec::new();
 8058                    for (range, new_text) in &edits {
 8059                        let inlay = Inlay::edit_prediction(
 8060                            post_inc(&mut self.next_inlay_id),
 8061                            range.start,
 8062                            new_text.as_ref(),
 8063                        );
 8064                        inlay_ids.push(inlay.id);
 8065                        inlays.push(inlay);
 8066                    }
 8067
 8068                    self.splice_inlays(&[], inlays, cx);
 8069                } else {
 8070                    let background_color = cx.theme().status().deleted_background;
 8071                    self.highlight_text::<EditPredictionHighlight>(
 8072                        edits.iter().map(|(range, _)| range.clone()).collect(),
 8073                        HighlightStyle {
 8074                            background_color: Some(background_color),
 8075                            ..Default::default()
 8076                        },
 8077                        cx,
 8078                    );
 8079                }
 8080            }
 8081
 8082            invalidation_row_range = edit_start_row..edit_end_row;
 8083
 8084            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 8085                if provider.show_tab_accept_marker() {
 8086                    EditDisplayMode::TabAccept
 8087                } else {
 8088                    EditDisplayMode::Inline
 8089                }
 8090            } else {
 8091                EditDisplayMode::DiffPopover
 8092            };
 8093
 8094            EditPrediction::Edit {
 8095                edits,
 8096                edit_preview,
 8097                display_mode,
 8098                snapshot,
 8099            }
 8100        };
 8101
 8102        let invalidation_range = multibuffer
 8103            .anchor_before(Point::new(invalidation_row_range.start, 0))
 8104            ..multibuffer.anchor_after(Point::new(
 8105                invalidation_row_range.end,
 8106                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 8107            ));
 8108
 8109        self.stale_edit_prediction_in_menu = None;
 8110        self.active_edit_prediction = Some(EditPredictionState {
 8111            inlay_ids,
 8112            completion,
 8113            completion_id,
 8114            invalidation_range: Some(invalidation_range),
 8115        });
 8116
 8117        cx.notify();
 8118
 8119        Some(())
 8120    }
 8121
 8122    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn EditPredictionProviderHandle>> {
 8123        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 8124    }
 8125
 8126    fn clear_tasks(&mut self) {
 8127        self.tasks.clear()
 8128    }
 8129
 8130    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 8131        if self.tasks.insert(key, value).is_some() {
 8132            // This case should hopefully be rare, but just in case...
 8133            log::error!(
 8134                "multiple different run targets found on a single line, only the last target will be rendered"
 8135            )
 8136        }
 8137    }
 8138
 8139    /// Get all display points of breakpoints that will be rendered within editor
 8140    ///
 8141    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 8142    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 8143    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 8144    fn active_breakpoints(
 8145        &self,
 8146        range: Range<DisplayRow>,
 8147        window: &mut Window,
 8148        cx: &mut Context<Self>,
 8149    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 8150        let mut breakpoint_display_points = HashMap::default();
 8151
 8152        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 8153            return breakpoint_display_points;
 8154        };
 8155
 8156        let snapshot = self.snapshot(window, cx);
 8157
 8158        let multi_buffer_snapshot = snapshot.buffer_snapshot();
 8159        let Some(project) = self.project() else {
 8160            return breakpoint_display_points;
 8161        };
 8162
 8163        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 8164            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 8165
 8166        for (buffer_snapshot, range, excerpt_id) in
 8167            multi_buffer_snapshot.range_to_buffer_ranges(range)
 8168        {
 8169            let Some(buffer) = project
 8170                .read(cx)
 8171                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 8172            else {
 8173                continue;
 8174            };
 8175            let breakpoints = breakpoint_store.read(cx).breakpoints(
 8176                &buffer,
 8177                Some(
 8178                    buffer_snapshot.anchor_before(range.start)
 8179                        ..buffer_snapshot.anchor_after(range.end),
 8180                ),
 8181                buffer_snapshot,
 8182                cx,
 8183            );
 8184            for (breakpoint, state) in breakpoints {
 8185                let multi_buffer_anchor =
 8186                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 8187                let position = multi_buffer_anchor
 8188                    .to_point(&multi_buffer_snapshot)
 8189                    .to_display_point(&snapshot);
 8190
 8191                breakpoint_display_points.insert(
 8192                    position.row(),
 8193                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 8194                );
 8195            }
 8196        }
 8197
 8198        breakpoint_display_points
 8199    }
 8200
 8201    fn breakpoint_context_menu(
 8202        &self,
 8203        anchor: Anchor,
 8204        window: &mut Window,
 8205        cx: &mut Context<Self>,
 8206    ) -> Entity<ui::ContextMenu> {
 8207        let weak_editor = cx.weak_entity();
 8208        let focus_handle = self.focus_handle(cx);
 8209
 8210        let row = self
 8211            .buffer
 8212            .read(cx)
 8213            .snapshot(cx)
 8214            .summary_for_anchor::<Point>(&anchor)
 8215            .row;
 8216
 8217        let breakpoint = self
 8218            .breakpoint_at_row(row, window, cx)
 8219            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 8220
 8221        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 8222            "Edit Log Breakpoint"
 8223        } else {
 8224            "Set Log Breakpoint"
 8225        };
 8226
 8227        let condition_breakpoint_msg = if breakpoint
 8228            .as_ref()
 8229            .is_some_and(|bp| bp.1.condition.is_some())
 8230        {
 8231            "Edit Condition Breakpoint"
 8232        } else {
 8233            "Set Condition Breakpoint"
 8234        };
 8235
 8236        let hit_condition_breakpoint_msg = if breakpoint
 8237            .as_ref()
 8238            .is_some_and(|bp| bp.1.hit_condition.is_some())
 8239        {
 8240            "Edit Hit Condition Breakpoint"
 8241        } else {
 8242            "Set Hit Condition Breakpoint"
 8243        };
 8244
 8245        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 8246            "Unset Breakpoint"
 8247        } else {
 8248            "Set Breakpoint"
 8249        };
 8250
 8251        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 8252
 8253        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 8254            BreakpointState::Enabled => Some("Disable"),
 8255            BreakpointState::Disabled => Some("Enable"),
 8256        });
 8257
 8258        let (anchor, breakpoint) =
 8259            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 8260
 8261        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 8262            menu.on_blur_subscription(Subscription::new(|| {}))
 8263                .context(focus_handle)
 8264                .when(run_to_cursor, |this| {
 8265                    let weak_editor = weak_editor.clone();
 8266                    this.entry("Run to cursor", None, move |window, cx| {
 8267                        weak_editor
 8268                            .update(cx, |editor, cx| {
 8269                                editor.change_selections(
 8270                                    SelectionEffects::no_scroll(),
 8271                                    window,
 8272                                    cx,
 8273                                    |s| s.select_ranges([Point::new(row, 0)..Point::new(row, 0)]),
 8274                                );
 8275                            })
 8276                            .ok();
 8277
 8278                        window.dispatch_action(Box::new(RunToCursor), cx);
 8279                    })
 8280                    .separator()
 8281                })
 8282                .when_some(toggle_state_msg, |this, msg| {
 8283                    this.entry(msg, None, {
 8284                        let weak_editor = weak_editor.clone();
 8285                        let breakpoint = breakpoint.clone();
 8286                        move |_window, cx| {
 8287                            weak_editor
 8288                                .update(cx, |this, cx| {
 8289                                    this.edit_breakpoint_at_anchor(
 8290                                        anchor,
 8291                                        breakpoint.as_ref().clone(),
 8292                                        BreakpointEditAction::InvertState,
 8293                                        cx,
 8294                                    );
 8295                                })
 8296                                .log_err();
 8297                        }
 8298                    })
 8299                })
 8300                .entry(set_breakpoint_msg, None, {
 8301                    let weak_editor = weak_editor.clone();
 8302                    let breakpoint = breakpoint.clone();
 8303                    move |_window, cx| {
 8304                        weak_editor
 8305                            .update(cx, |this, cx| {
 8306                                this.edit_breakpoint_at_anchor(
 8307                                    anchor,
 8308                                    breakpoint.as_ref().clone(),
 8309                                    BreakpointEditAction::Toggle,
 8310                                    cx,
 8311                                );
 8312                            })
 8313                            .log_err();
 8314                    }
 8315                })
 8316                .entry(log_breakpoint_msg, None, {
 8317                    let breakpoint = breakpoint.clone();
 8318                    let weak_editor = weak_editor.clone();
 8319                    move |window, cx| {
 8320                        weak_editor
 8321                            .update(cx, |this, cx| {
 8322                                this.add_edit_breakpoint_block(
 8323                                    anchor,
 8324                                    breakpoint.as_ref(),
 8325                                    BreakpointPromptEditAction::Log,
 8326                                    window,
 8327                                    cx,
 8328                                );
 8329                            })
 8330                            .log_err();
 8331                    }
 8332                })
 8333                .entry(condition_breakpoint_msg, None, {
 8334                    let breakpoint = breakpoint.clone();
 8335                    let weak_editor = weak_editor.clone();
 8336                    move |window, cx| {
 8337                        weak_editor
 8338                            .update(cx, |this, cx| {
 8339                                this.add_edit_breakpoint_block(
 8340                                    anchor,
 8341                                    breakpoint.as_ref(),
 8342                                    BreakpointPromptEditAction::Condition,
 8343                                    window,
 8344                                    cx,
 8345                                );
 8346                            })
 8347                            .log_err();
 8348                    }
 8349                })
 8350                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 8351                    weak_editor
 8352                        .update(cx, |this, cx| {
 8353                            this.add_edit_breakpoint_block(
 8354                                anchor,
 8355                                breakpoint.as_ref(),
 8356                                BreakpointPromptEditAction::HitCondition,
 8357                                window,
 8358                                cx,
 8359                            );
 8360                        })
 8361                        .log_err();
 8362                })
 8363        })
 8364    }
 8365
 8366    fn render_breakpoint(
 8367        &self,
 8368        position: Anchor,
 8369        row: DisplayRow,
 8370        breakpoint: &Breakpoint,
 8371        state: Option<BreakpointSessionState>,
 8372        cx: &mut Context<Self>,
 8373    ) -> IconButton {
 8374        let is_rejected = state.is_some_and(|s| !s.verified);
 8375        // Is it a breakpoint that shows up when hovering over gutter?
 8376        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 8377            (false, false),
 8378            |PhantomBreakpointIndicator {
 8379                 is_active,
 8380                 display_row,
 8381                 collides_with_existing_breakpoint,
 8382             }| {
 8383                (
 8384                    is_active && display_row == row,
 8385                    collides_with_existing_breakpoint,
 8386                )
 8387            },
 8388        );
 8389
 8390        let (color, icon) = {
 8391            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 8392                (false, false) => ui::IconName::DebugBreakpoint,
 8393                (true, false) => ui::IconName::DebugLogBreakpoint,
 8394                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 8395                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 8396            };
 8397
 8398            let color = if is_phantom {
 8399                Color::Hint
 8400            } else if is_rejected {
 8401                Color::Disabled
 8402            } else {
 8403                Color::Debugger
 8404            };
 8405
 8406            (color, icon)
 8407        };
 8408
 8409        let breakpoint = Arc::from(breakpoint.clone());
 8410
 8411        let alt_as_text = gpui::Keystroke {
 8412            modifiers: Modifiers::secondary_key(),
 8413            ..Default::default()
 8414        };
 8415        let primary_action_text = if breakpoint.is_disabled() {
 8416            "Enable breakpoint"
 8417        } else if is_phantom && !collides_with_existing {
 8418            "Set breakpoint"
 8419        } else {
 8420            "Unset breakpoint"
 8421        };
 8422        let focus_handle = self.focus_handle.clone();
 8423
 8424        let meta = if is_rejected {
 8425            SharedString::from("No executable code is associated with this line.")
 8426        } else if collides_with_existing && !breakpoint.is_disabled() {
 8427            SharedString::from(format!(
 8428                "{alt_as_text}-click to disable,\nright-click for more options."
 8429            ))
 8430        } else {
 8431            SharedString::from("Right-click for more options.")
 8432        };
 8433        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 8434            .icon_size(IconSize::XSmall)
 8435            .size(ui::ButtonSize::None)
 8436            .when(is_rejected, |this| {
 8437                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 8438            })
 8439            .icon_color(color)
 8440            .style(ButtonStyle::Transparent)
 8441            .on_click(cx.listener({
 8442                move |editor, event: &ClickEvent, window, cx| {
 8443                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 8444                        BreakpointEditAction::InvertState
 8445                    } else {
 8446                        BreakpointEditAction::Toggle
 8447                    };
 8448
 8449                    window.focus(&editor.focus_handle(cx));
 8450                    editor.edit_breakpoint_at_anchor(
 8451                        position,
 8452                        breakpoint.as_ref().clone(),
 8453                        edit_action,
 8454                        cx,
 8455                    );
 8456                }
 8457            }))
 8458            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8459                editor.set_breakpoint_context_menu(
 8460                    row,
 8461                    Some(position),
 8462                    event.position(),
 8463                    window,
 8464                    cx,
 8465                );
 8466            }))
 8467            .tooltip(move |_window, cx| {
 8468                Tooltip::with_meta_in(
 8469                    primary_action_text,
 8470                    Some(&ToggleBreakpoint),
 8471                    meta.clone(),
 8472                    &focus_handle,
 8473                    cx,
 8474                )
 8475            })
 8476    }
 8477
 8478    fn build_tasks_context(
 8479        project: &Entity<Project>,
 8480        buffer: &Entity<Buffer>,
 8481        buffer_row: u32,
 8482        tasks: &Arc<RunnableTasks>,
 8483        cx: &mut Context<Self>,
 8484    ) -> Task<Option<task::TaskContext>> {
 8485        let position = Point::new(buffer_row, tasks.column);
 8486        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 8487        let location = Location {
 8488            buffer: buffer.clone(),
 8489            range: range_start..range_start,
 8490        };
 8491        // Fill in the environmental variables from the tree-sitter captures
 8492        let mut captured_task_variables = TaskVariables::default();
 8493        for (capture_name, value) in tasks.extra_variables.clone() {
 8494            captured_task_variables.insert(
 8495                task::VariableName::Custom(capture_name.into()),
 8496                value.clone(),
 8497            );
 8498        }
 8499        project.update(cx, |project, cx| {
 8500            project.task_store().update(cx, |task_store, cx| {
 8501                task_store.task_context_for_location(captured_task_variables, location, cx)
 8502            })
 8503        })
 8504    }
 8505
 8506    pub fn spawn_nearest_task(
 8507        &mut self,
 8508        action: &SpawnNearestTask,
 8509        window: &mut Window,
 8510        cx: &mut Context<Self>,
 8511    ) {
 8512        let Some((workspace, _)) = self.workspace.clone() else {
 8513            return;
 8514        };
 8515        let Some(project) = self.project.clone() else {
 8516            return;
 8517        };
 8518
 8519        // Try to find a closest, enclosing node using tree-sitter that has a task
 8520        let Some((buffer, buffer_row, tasks)) = self
 8521            .find_enclosing_node_task(cx)
 8522            // Or find the task that's closest in row-distance.
 8523            .or_else(|| self.find_closest_task(cx))
 8524        else {
 8525            return;
 8526        };
 8527
 8528        let reveal_strategy = action.reveal;
 8529        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 8530        cx.spawn_in(window, async move |_, cx| {
 8531            let context = task_context.await?;
 8532            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 8533
 8534            let resolved = &mut resolved_task.resolved;
 8535            resolved.reveal = reveal_strategy;
 8536
 8537            workspace
 8538                .update_in(cx, |workspace, window, cx| {
 8539                    workspace.schedule_resolved_task(
 8540                        task_source_kind,
 8541                        resolved_task,
 8542                        false,
 8543                        window,
 8544                        cx,
 8545                    );
 8546                })
 8547                .ok()
 8548        })
 8549        .detach();
 8550    }
 8551
 8552    fn find_closest_task(
 8553        &mut self,
 8554        cx: &mut Context<Self>,
 8555    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8556        let cursor_row = self
 8557            .selections
 8558            .newest_adjusted(&self.display_snapshot(cx))
 8559            .head()
 8560            .row;
 8561
 8562        let ((buffer_id, row), tasks) = self
 8563            .tasks
 8564            .iter()
 8565            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 8566
 8567        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 8568        let tasks = Arc::new(tasks.to_owned());
 8569        Some((buffer, *row, tasks))
 8570    }
 8571
 8572    fn find_enclosing_node_task(
 8573        &mut self,
 8574        cx: &mut Context<Self>,
 8575    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8576        let snapshot = self.buffer.read(cx).snapshot(cx);
 8577        let offset = self
 8578            .selections
 8579            .newest::<usize>(&self.display_snapshot(cx))
 8580            .head();
 8581        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 8582        let buffer_id = excerpt.buffer().remote_id();
 8583
 8584        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 8585        let mut cursor = layer.node().walk();
 8586
 8587        while cursor.goto_first_child_for_byte(offset).is_some() {
 8588            if cursor.node().end_byte() == offset {
 8589                cursor.goto_next_sibling();
 8590            }
 8591        }
 8592
 8593        // Ascend to the smallest ancestor that contains the range and has a task.
 8594        loop {
 8595            let node = cursor.node();
 8596            let node_range = node.byte_range();
 8597            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 8598
 8599            // Check if this node contains our offset
 8600            if node_range.start <= offset && node_range.end >= offset {
 8601                // If it contains offset, check for task
 8602                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 8603                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 8604                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 8605                }
 8606            }
 8607
 8608            if !cursor.goto_parent() {
 8609                break;
 8610            }
 8611        }
 8612        None
 8613    }
 8614
 8615    fn render_run_indicator(
 8616        &self,
 8617        _style: &EditorStyle,
 8618        is_active: bool,
 8619        row: DisplayRow,
 8620        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 8621        cx: &mut Context<Self>,
 8622    ) -> IconButton {
 8623        let color = Color::Muted;
 8624        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 8625
 8626        IconButton::new(
 8627            ("run_indicator", row.0 as usize),
 8628            ui::IconName::PlayOutlined,
 8629        )
 8630        .shape(ui::IconButtonShape::Square)
 8631        .icon_size(IconSize::XSmall)
 8632        .icon_color(color)
 8633        .toggle_state(is_active)
 8634        .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 8635            let quick_launch = match e {
 8636                ClickEvent::Keyboard(_) => true,
 8637                ClickEvent::Mouse(e) => e.down.button == MouseButton::Left,
 8638            };
 8639
 8640            window.focus(&editor.focus_handle(cx));
 8641            editor.toggle_code_actions(
 8642                &ToggleCodeActions {
 8643                    deployed_from: Some(CodeActionSource::RunMenu(row)),
 8644                    quick_launch,
 8645                },
 8646                window,
 8647                cx,
 8648            );
 8649        }))
 8650        .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8651            editor.set_breakpoint_context_menu(row, position, event.position(), window, cx);
 8652        }))
 8653    }
 8654
 8655    pub fn context_menu_visible(&self) -> bool {
 8656        !self.edit_prediction_preview_is_active()
 8657            && self
 8658                .context_menu
 8659                .borrow()
 8660                .as_ref()
 8661                .is_some_and(|menu| menu.visible())
 8662    }
 8663
 8664    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 8665        self.context_menu
 8666            .borrow()
 8667            .as_ref()
 8668            .map(|menu| menu.origin())
 8669    }
 8670
 8671    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 8672        self.context_menu_options = Some(options);
 8673    }
 8674
 8675    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = px(24.);
 8676    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = px(2.);
 8677
 8678    fn render_edit_prediction_popover(
 8679        &mut self,
 8680        text_bounds: &Bounds<Pixels>,
 8681        content_origin: gpui::Point<Pixels>,
 8682        right_margin: Pixels,
 8683        editor_snapshot: &EditorSnapshot,
 8684        visible_row_range: Range<DisplayRow>,
 8685        scroll_top: ScrollOffset,
 8686        scroll_bottom: ScrollOffset,
 8687        line_layouts: &[LineWithInvisibles],
 8688        line_height: Pixels,
 8689        scroll_position: gpui::Point<ScrollOffset>,
 8690        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8691        newest_selection_head: Option<DisplayPoint>,
 8692        editor_width: Pixels,
 8693        style: &EditorStyle,
 8694        window: &mut Window,
 8695        cx: &mut App,
 8696    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8697        if self.mode().is_minimap() {
 8698            return None;
 8699        }
 8700        let active_edit_prediction = self.active_edit_prediction.as_ref()?;
 8701
 8702        if self.edit_prediction_visible_in_cursor_popover(true) {
 8703            return None;
 8704        }
 8705
 8706        match &active_edit_prediction.completion {
 8707            EditPrediction::MoveWithin { target, .. } => {
 8708                let target_display_point = target.to_display_point(editor_snapshot);
 8709
 8710                if self.edit_prediction_requires_modifier() {
 8711                    if !self.edit_prediction_preview_is_active() {
 8712                        return None;
 8713                    }
 8714
 8715                    self.render_edit_prediction_modifier_jump_popover(
 8716                        text_bounds,
 8717                        content_origin,
 8718                        visible_row_range,
 8719                        line_layouts,
 8720                        line_height,
 8721                        scroll_pixel_position,
 8722                        newest_selection_head,
 8723                        target_display_point,
 8724                        window,
 8725                        cx,
 8726                    )
 8727                } else {
 8728                    self.render_edit_prediction_eager_jump_popover(
 8729                        text_bounds,
 8730                        content_origin,
 8731                        editor_snapshot,
 8732                        visible_row_range,
 8733                        scroll_top,
 8734                        scroll_bottom,
 8735                        line_height,
 8736                        scroll_pixel_position,
 8737                        target_display_point,
 8738                        editor_width,
 8739                        window,
 8740                        cx,
 8741                    )
 8742                }
 8743            }
 8744            EditPrediction::Edit {
 8745                display_mode: EditDisplayMode::Inline,
 8746                ..
 8747            } => None,
 8748            EditPrediction::Edit {
 8749                display_mode: EditDisplayMode::TabAccept,
 8750                edits,
 8751                ..
 8752            } => {
 8753                let range = &edits.first()?.0;
 8754                let target_display_point = range.end.to_display_point(editor_snapshot);
 8755
 8756                self.render_edit_prediction_end_of_line_popover(
 8757                    "Accept",
 8758                    editor_snapshot,
 8759                    visible_row_range,
 8760                    target_display_point,
 8761                    line_height,
 8762                    scroll_pixel_position,
 8763                    content_origin,
 8764                    editor_width,
 8765                    window,
 8766                    cx,
 8767                )
 8768            }
 8769            EditPrediction::Edit {
 8770                edits,
 8771                edit_preview,
 8772                display_mode: EditDisplayMode::DiffPopover,
 8773                snapshot,
 8774            } => self.render_edit_prediction_diff_popover(
 8775                text_bounds,
 8776                content_origin,
 8777                right_margin,
 8778                editor_snapshot,
 8779                visible_row_range,
 8780                line_layouts,
 8781                line_height,
 8782                scroll_position,
 8783                scroll_pixel_position,
 8784                newest_selection_head,
 8785                editor_width,
 8786                style,
 8787                edits,
 8788                edit_preview,
 8789                snapshot,
 8790                window,
 8791                cx,
 8792            ),
 8793            EditPrediction::MoveOutside { snapshot, .. } => {
 8794                let file_name = snapshot
 8795                    .file()
 8796                    .map(|file| file.file_name(cx))
 8797                    .unwrap_or("untitled");
 8798                let mut element = self
 8799                    .render_edit_prediction_line_popover(
 8800                        format!("Jump to {file_name}"),
 8801                        Some(IconName::ZedPredict),
 8802                        window,
 8803                        cx,
 8804                    )
 8805                    .into_any();
 8806
 8807                let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8808                let origin_x = text_bounds.size.width / 2. - size.width / 2.;
 8809                let origin_y = text_bounds.size.height - size.height - px(30.);
 8810                let origin = text_bounds.origin + gpui::Point::new(origin_x, origin_y);
 8811                element.prepaint_at(origin, window, cx);
 8812
 8813                Some((element, origin))
 8814            }
 8815        }
 8816    }
 8817
 8818    fn render_edit_prediction_modifier_jump_popover(
 8819        &mut self,
 8820        text_bounds: &Bounds<Pixels>,
 8821        content_origin: gpui::Point<Pixels>,
 8822        visible_row_range: Range<DisplayRow>,
 8823        line_layouts: &[LineWithInvisibles],
 8824        line_height: Pixels,
 8825        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8826        newest_selection_head: Option<DisplayPoint>,
 8827        target_display_point: DisplayPoint,
 8828        window: &mut Window,
 8829        cx: &mut App,
 8830    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8831        let scrolled_content_origin =
 8832            content_origin - gpui::Point::new(scroll_pixel_position.x.into(), Pixels::ZERO);
 8833
 8834        const SCROLL_PADDING_Y: Pixels = px(12.);
 8835
 8836        if target_display_point.row() < visible_row_range.start {
 8837            return self.render_edit_prediction_scroll_popover(
 8838                |_| SCROLL_PADDING_Y,
 8839                IconName::ArrowUp,
 8840                visible_row_range,
 8841                line_layouts,
 8842                newest_selection_head,
 8843                scrolled_content_origin,
 8844                window,
 8845                cx,
 8846            );
 8847        } else if target_display_point.row() >= visible_row_range.end {
 8848            return self.render_edit_prediction_scroll_popover(
 8849                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 8850                IconName::ArrowDown,
 8851                visible_row_range,
 8852                line_layouts,
 8853                newest_selection_head,
 8854                scrolled_content_origin,
 8855                window,
 8856                cx,
 8857            );
 8858        }
 8859
 8860        const POLE_WIDTH: Pixels = px(2.);
 8861
 8862        let line_layout =
 8863            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 8864        let target_column = target_display_point.column() as usize;
 8865
 8866        let target_x = line_layout.x_for_index(target_column);
 8867        let target_y = (target_display_point.row().as_f64() * f64::from(line_height))
 8868            - scroll_pixel_position.y;
 8869
 8870        let flag_on_right = target_x < text_bounds.size.width / 2.;
 8871
 8872        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 8873        border_color.l += 0.001;
 8874
 8875        let mut element = v_flex()
 8876            .items_end()
 8877            .when(flag_on_right, |el| el.items_start())
 8878            .child(if flag_on_right {
 8879                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 8880                    .rounded_bl(px(0.))
 8881                    .rounded_tl(px(0.))
 8882                    .border_l_2()
 8883                    .border_color(border_color)
 8884            } else {
 8885                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 8886                    .rounded_br(px(0.))
 8887                    .rounded_tr(px(0.))
 8888                    .border_r_2()
 8889                    .border_color(border_color)
 8890            })
 8891            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 8892            .into_any();
 8893
 8894        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8895
 8896        let mut origin = scrolled_content_origin + point(target_x, target_y.into())
 8897            - point(
 8898                if flag_on_right {
 8899                    POLE_WIDTH
 8900                } else {
 8901                    size.width - POLE_WIDTH
 8902                },
 8903                size.height - line_height,
 8904            );
 8905
 8906        origin.x = origin.x.max(content_origin.x);
 8907
 8908        element.prepaint_at(origin, window, cx);
 8909
 8910        Some((element, origin))
 8911    }
 8912
 8913    fn render_edit_prediction_scroll_popover(
 8914        &mut self,
 8915        to_y: impl Fn(Size<Pixels>) -> Pixels,
 8916        scroll_icon: IconName,
 8917        visible_row_range: Range<DisplayRow>,
 8918        line_layouts: &[LineWithInvisibles],
 8919        newest_selection_head: Option<DisplayPoint>,
 8920        scrolled_content_origin: gpui::Point<Pixels>,
 8921        window: &mut Window,
 8922        cx: &mut App,
 8923    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8924        let mut element = self
 8925            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)
 8926            .into_any();
 8927
 8928        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8929
 8930        let cursor = newest_selection_head?;
 8931        let cursor_row_layout =
 8932            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 8933        let cursor_column = cursor.column() as usize;
 8934
 8935        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 8936
 8937        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 8938
 8939        element.prepaint_at(origin, window, cx);
 8940        Some((element, origin))
 8941    }
 8942
 8943    fn render_edit_prediction_eager_jump_popover(
 8944        &mut self,
 8945        text_bounds: &Bounds<Pixels>,
 8946        content_origin: gpui::Point<Pixels>,
 8947        editor_snapshot: &EditorSnapshot,
 8948        visible_row_range: Range<DisplayRow>,
 8949        scroll_top: ScrollOffset,
 8950        scroll_bottom: ScrollOffset,
 8951        line_height: Pixels,
 8952        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8953        target_display_point: DisplayPoint,
 8954        editor_width: Pixels,
 8955        window: &mut Window,
 8956        cx: &mut App,
 8957    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8958        if target_display_point.row().as_f64() < scroll_top {
 8959            let mut element = self
 8960                .render_edit_prediction_line_popover(
 8961                    "Jump to Edit",
 8962                    Some(IconName::ArrowUp),
 8963                    window,
 8964                    cx,
 8965                )
 8966                .into_any();
 8967
 8968            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8969            let offset = point(
 8970                (text_bounds.size.width - size.width) / 2.,
 8971                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8972            );
 8973
 8974            let origin = text_bounds.origin + offset;
 8975            element.prepaint_at(origin, window, cx);
 8976            Some((element, origin))
 8977        } else if (target_display_point.row().as_f64() + 1.) > scroll_bottom {
 8978            let mut element = self
 8979                .render_edit_prediction_line_popover(
 8980                    "Jump to Edit",
 8981                    Some(IconName::ArrowDown),
 8982                    window,
 8983                    cx,
 8984                )
 8985                .into_any();
 8986
 8987            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8988            let offset = point(
 8989                (text_bounds.size.width - size.width) / 2.,
 8990                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8991            );
 8992
 8993            let origin = text_bounds.origin + offset;
 8994            element.prepaint_at(origin, window, cx);
 8995            Some((element, origin))
 8996        } else {
 8997            self.render_edit_prediction_end_of_line_popover(
 8998                "Jump to Edit",
 8999                editor_snapshot,
 9000                visible_row_range,
 9001                target_display_point,
 9002                line_height,
 9003                scroll_pixel_position,
 9004                content_origin,
 9005                editor_width,
 9006                window,
 9007                cx,
 9008            )
 9009        }
 9010    }
 9011
 9012    fn render_edit_prediction_end_of_line_popover(
 9013        self: &mut Editor,
 9014        label: &'static str,
 9015        editor_snapshot: &EditorSnapshot,
 9016        visible_row_range: Range<DisplayRow>,
 9017        target_display_point: DisplayPoint,
 9018        line_height: Pixels,
 9019        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9020        content_origin: gpui::Point<Pixels>,
 9021        editor_width: Pixels,
 9022        window: &mut Window,
 9023        cx: &mut App,
 9024    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9025        let target_line_end = DisplayPoint::new(
 9026            target_display_point.row(),
 9027            editor_snapshot.line_len(target_display_point.row()),
 9028        );
 9029
 9030        let mut element = self
 9031            .render_edit_prediction_line_popover(label, None, window, cx)
 9032            .into_any();
 9033
 9034        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9035
 9036        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 9037
 9038        let start_point = content_origin - point(scroll_pixel_position.x.into(), Pixels::ZERO);
 9039        let mut origin = start_point
 9040            + line_origin
 9041            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 9042        origin.x = origin.x.max(content_origin.x);
 9043
 9044        let max_x = content_origin.x + editor_width - size.width;
 9045
 9046        if origin.x > max_x {
 9047            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 9048
 9049            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 9050                origin.y += offset;
 9051                IconName::ArrowUp
 9052            } else {
 9053                origin.y -= offset;
 9054                IconName::ArrowDown
 9055            };
 9056
 9057            element = self
 9058                .render_edit_prediction_line_popover(label, Some(icon), window, cx)
 9059                .into_any();
 9060
 9061            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9062
 9063            origin.x = content_origin.x + editor_width - size.width - px(2.);
 9064        }
 9065
 9066        element.prepaint_at(origin, window, cx);
 9067        Some((element, origin))
 9068    }
 9069
 9070    fn render_edit_prediction_diff_popover(
 9071        self: &Editor,
 9072        text_bounds: &Bounds<Pixels>,
 9073        content_origin: gpui::Point<Pixels>,
 9074        right_margin: Pixels,
 9075        editor_snapshot: &EditorSnapshot,
 9076        visible_row_range: Range<DisplayRow>,
 9077        line_layouts: &[LineWithInvisibles],
 9078        line_height: Pixels,
 9079        scroll_position: gpui::Point<ScrollOffset>,
 9080        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9081        newest_selection_head: Option<DisplayPoint>,
 9082        editor_width: Pixels,
 9083        style: &EditorStyle,
 9084        edits: &Vec<(Range<Anchor>, Arc<str>)>,
 9085        edit_preview: &Option<language::EditPreview>,
 9086        snapshot: &language::BufferSnapshot,
 9087        window: &mut Window,
 9088        cx: &mut App,
 9089    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9090        let edit_start = edits
 9091            .first()
 9092            .unwrap()
 9093            .0
 9094            .start
 9095            .to_display_point(editor_snapshot);
 9096        let edit_end = edits
 9097            .last()
 9098            .unwrap()
 9099            .0
 9100            .end
 9101            .to_display_point(editor_snapshot);
 9102
 9103        let is_visible = visible_row_range.contains(&edit_start.row())
 9104            || visible_row_range.contains(&edit_end.row());
 9105        if !is_visible {
 9106            return None;
 9107        }
 9108
 9109        let highlighted_edits = if let Some(edit_preview) = edit_preview.as_ref() {
 9110            crate::edit_prediction_edit_text(snapshot, edits, edit_preview, false, cx)
 9111        } else {
 9112            // Fallback for providers without edit_preview
 9113            crate::edit_prediction_fallback_text(edits, cx)
 9114        };
 9115
 9116        let styled_text = highlighted_edits.to_styled_text(&style.text);
 9117        let line_count = highlighted_edits.text.lines().count();
 9118
 9119        const BORDER_WIDTH: Pixels = px(1.);
 9120
 9121        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9122        let has_keybind = keybind.is_some();
 9123
 9124        let mut element = h_flex()
 9125            .items_start()
 9126            .child(
 9127                h_flex()
 9128                    .bg(cx.theme().colors().editor_background)
 9129                    .border(BORDER_WIDTH)
 9130                    .shadow_xs()
 9131                    .border_color(cx.theme().colors().border)
 9132                    .rounded_l_lg()
 9133                    .when(line_count > 1, |el| el.rounded_br_lg())
 9134                    .pr_1()
 9135                    .child(styled_text),
 9136            )
 9137            .child(
 9138                h_flex()
 9139                    .h(line_height + BORDER_WIDTH * 2.)
 9140                    .px_1p5()
 9141                    .gap_1()
 9142                    // Workaround: For some reason, there's a gap if we don't do this
 9143                    .ml(-BORDER_WIDTH)
 9144                    .shadow(vec![gpui::BoxShadow {
 9145                        color: gpui::black().opacity(0.05),
 9146                        offset: point(px(1.), px(1.)),
 9147                        blur_radius: px(2.),
 9148                        spread_radius: px(0.),
 9149                    }])
 9150                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 9151                    .border(BORDER_WIDTH)
 9152                    .border_color(cx.theme().colors().border)
 9153                    .rounded_r_lg()
 9154                    .id("edit_prediction_diff_popover_keybind")
 9155                    .when(!has_keybind, |el| {
 9156                        let status_colors = cx.theme().status();
 9157
 9158                        el.bg(status_colors.error_background)
 9159                            .border_color(status_colors.error.opacity(0.6))
 9160                            .child(Icon::new(IconName::Info).color(Color::Error))
 9161                            .cursor_default()
 9162                            .hoverable_tooltip(move |_window, cx| {
 9163                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9164                            })
 9165                    })
 9166                    .children(keybind),
 9167            )
 9168            .into_any();
 9169
 9170        let longest_row =
 9171            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 9172        let longest_line_width = if visible_row_range.contains(&longest_row) {
 9173            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 9174        } else {
 9175            layout_line(
 9176                longest_row,
 9177                editor_snapshot,
 9178                style,
 9179                editor_width,
 9180                |_| false,
 9181                window,
 9182                cx,
 9183            )
 9184            .width
 9185        };
 9186
 9187        let viewport_bounds =
 9188            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 9189                right: -right_margin,
 9190                ..Default::default()
 9191            });
 9192
 9193        let x_after_longest = Pixels::from(
 9194            ScrollPixelOffset::from(
 9195                text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X,
 9196            ) - scroll_pixel_position.x,
 9197        );
 9198
 9199        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9200
 9201        // Fully visible if it can be displayed within the window (allow overlapping other
 9202        // panes). However, this is only allowed if the popover starts within text_bounds.
 9203        let can_position_to_the_right = x_after_longest < text_bounds.right()
 9204            && x_after_longest + element_bounds.width < viewport_bounds.right();
 9205
 9206        let mut origin = if can_position_to_the_right {
 9207            point(
 9208                x_after_longest,
 9209                text_bounds.origin.y
 9210                    + Pixels::from(
 9211                        edit_start.row().as_f64() * ScrollPixelOffset::from(line_height)
 9212                            - scroll_pixel_position.y,
 9213                    ),
 9214            )
 9215        } else {
 9216            let cursor_row = newest_selection_head.map(|head| head.row());
 9217            let above_edit = edit_start
 9218                .row()
 9219                .0
 9220                .checked_sub(line_count as u32)
 9221                .map(DisplayRow);
 9222            let below_edit = Some(edit_end.row() + 1);
 9223            let above_cursor =
 9224                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 9225            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 9226
 9227            // Place the edit popover adjacent to the edit if there is a location
 9228            // available that is onscreen and does not obscure the cursor. Otherwise,
 9229            // place it adjacent to the cursor.
 9230            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 9231                .into_iter()
 9232                .flatten()
 9233                .find(|&start_row| {
 9234                    let end_row = start_row + line_count as u32;
 9235                    visible_row_range.contains(&start_row)
 9236                        && visible_row_range.contains(&end_row)
 9237                        && cursor_row
 9238                            .is_none_or(|cursor_row| !((start_row..end_row).contains(&cursor_row)))
 9239                })?;
 9240
 9241            content_origin
 9242                + point(
 9243                    Pixels::from(-scroll_pixel_position.x),
 9244                    Pixels::from(
 9245                        (row_target.as_f64() - scroll_position.y) * f64::from(line_height),
 9246                    ),
 9247                )
 9248        };
 9249
 9250        origin.x -= BORDER_WIDTH;
 9251
 9252        window.defer_draw(element, origin, 1);
 9253
 9254        // Do not return an element, since it will already be drawn due to defer_draw.
 9255        None
 9256    }
 9257
 9258    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 9259        px(30.)
 9260    }
 9261
 9262    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 9263        if self.read_only(cx) {
 9264            cx.theme().players().read_only()
 9265        } else {
 9266            self.style.as_ref().unwrap().local_player
 9267        }
 9268    }
 9269
 9270    fn render_edit_prediction_accept_keybind(
 9271        &self,
 9272        window: &mut Window,
 9273        cx: &mut App,
 9274    ) -> Option<AnyElement> {
 9275        let accept_binding = self.accept_edit_prediction_keybind(false, window, cx);
 9276        let accept_keystroke = accept_binding.keystroke()?;
 9277
 9278        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9279
 9280        let modifiers_color = if *accept_keystroke.modifiers() == window.modifiers() {
 9281            Color::Accent
 9282        } else {
 9283            Color::Muted
 9284        };
 9285
 9286        h_flex()
 9287            .px_0p5()
 9288            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 9289            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9290            .text_size(TextSize::XSmall.rems(cx))
 9291            .child(h_flex().children(ui::render_modifiers(
 9292                accept_keystroke.modifiers(),
 9293                PlatformStyle::platform(),
 9294                Some(modifiers_color),
 9295                Some(IconSize::XSmall.rems().into()),
 9296                true,
 9297            )))
 9298            .when(is_platform_style_mac, |parent| {
 9299                parent.child(accept_keystroke.key().to_string())
 9300            })
 9301            .when(!is_platform_style_mac, |parent| {
 9302                parent.child(
 9303                    Key::new(
 9304                        util::capitalize(accept_keystroke.key()),
 9305                        Some(Color::Default),
 9306                    )
 9307                    .size(Some(IconSize::XSmall.rems().into())),
 9308                )
 9309            })
 9310            .into_any()
 9311            .into()
 9312    }
 9313
 9314    fn render_edit_prediction_line_popover(
 9315        &self,
 9316        label: impl Into<SharedString>,
 9317        icon: Option<IconName>,
 9318        window: &mut Window,
 9319        cx: &mut App,
 9320    ) -> Stateful<Div> {
 9321        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 9322
 9323        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9324        let has_keybind = keybind.is_some();
 9325
 9326        h_flex()
 9327            .id("ep-line-popover")
 9328            .py_0p5()
 9329            .pl_1()
 9330            .pr(padding_right)
 9331            .gap_1()
 9332            .rounded_md()
 9333            .border_1()
 9334            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9335            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9336            .shadow_xs()
 9337            .when(!has_keybind, |el| {
 9338                let status_colors = cx.theme().status();
 9339
 9340                el.bg(status_colors.error_background)
 9341                    .border_color(status_colors.error.opacity(0.6))
 9342                    .pl_2()
 9343                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9344                    .cursor_default()
 9345                    .hoverable_tooltip(move |_window, cx| {
 9346                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9347                    })
 9348            })
 9349            .children(keybind)
 9350            .child(
 9351                Label::new(label)
 9352                    .size(LabelSize::Small)
 9353                    .when(!has_keybind, |el| {
 9354                        el.color(cx.theme().status().error.into()).strikethrough()
 9355                    }),
 9356            )
 9357            .when(!has_keybind, |el| {
 9358                el.child(
 9359                    h_flex().ml_1().child(
 9360                        Icon::new(IconName::Info)
 9361                            .size(IconSize::Small)
 9362                            .color(cx.theme().status().error.into()),
 9363                    ),
 9364                )
 9365            })
 9366            .when_some(icon, |element, icon| {
 9367                element.child(
 9368                    div()
 9369                        .mt(px(1.5))
 9370                        .child(Icon::new(icon).size(IconSize::Small)),
 9371                )
 9372            })
 9373    }
 9374
 9375    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 9376        let accent_color = cx.theme().colors().text_accent;
 9377        let editor_bg_color = cx.theme().colors().editor_background;
 9378        editor_bg_color.blend(accent_color.opacity(0.1))
 9379    }
 9380
 9381    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 9382        let accent_color = cx.theme().colors().text_accent;
 9383        let editor_bg_color = cx.theme().colors().editor_background;
 9384        editor_bg_color.blend(accent_color.opacity(0.6))
 9385    }
 9386    fn get_prediction_provider_icon_name(
 9387        provider: &Option<RegisteredEditPredictionProvider>,
 9388    ) -> IconName {
 9389        match provider {
 9390            Some(provider) => match provider.provider.name() {
 9391                "copilot" => IconName::Copilot,
 9392                "supermaven" => IconName::Supermaven,
 9393                _ => IconName::ZedPredict,
 9394            },
 9395            None => IconName::ZedPredict,
 9396        }
 9397    }
 9398
 9399    fn render_edit_prediction_cursor_popover(
 9400        &self,
 9401        min_width: Pixels,
 9402        max_width: Pixels,
 9403        cursor_point: Point,
 9404        style: &EditorStyle,
 9405        accept_keystroke: Option<&gpui::KeybindingKeystroke>,
 9406        _window: &Window,
 9407        cx: &mut Context<Editor>,
 9408    ) -> Option<AnyElement> {
 9409        let provider = self.edit_prediction_provider.as_ref()?;
 9410        let provider_icon = Self::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9411
 9412        let is_refreshing = provider.provider.is_refreshing(cx);
 9413
 9414        fn pending_completion_container(icon: IconName) -> Div {
 9415            h_flex().h_full().flex_1().gap_2().child(Icon::new(icon))
 9416        }
 9417
 9418        let completion = match &self.active_edit_prediction {
 9419            Some(prediction) => {
 9420                if !self.has_visible_completions_menu() {
 9421                    const RADIUS: Pixels = px(6.);
 9422                    const BORDER_WIDTH: Pixels = px(1.);
 9423
 9424                    return Some(
 9425                        h_flex()
 9426                            .elevation_2(cx)
 9427                            .border(BORDER_WIDTH)
 9428                            .border_color(cx.theme().colors().border)
 9429                            .when(accept_keystroke.is_none(), |el| {
 9430                                el.border_color(cx.theme().status().error)
 9431                            })
 9432                            .rounded(RADIUS)
 9433                            .rounded_tl(px(0.))
 9434                            .overflow_hidden()
 9435                            .child(div().px_1p5().child(match &prediction.completion {
 9436                                EditPrediction::MoveWithin { target, snapshot } => {
 9437                                    use text::ToPoint as _;
 9438                                    if target.text_anchor.to_point(snapshot).row > cursor_point.row
 9439                                    {
 9440                                        Icon::new(IconName::ZedPredictDown)
 9441                                    } else {
 9442                                        Icon::new(IconName::ZedPredictUp)
 9443                                    }
 9444                                }
 9445                                EditPrediction::MoveOutside { .. } => {
 9446                                    // TODO [zeta2] custom icon for external jump?
 9447                                    Icon::new(provider_icon)
 9448                                }
 9449                                EditPrediction::Edit { .. } => Icon::new(provider_icon),
 9450                            }))
 9451                            .child(
 9452                                h_flex()
 9453                                    .gap_1()
 9454                                    .py_1()
 9455                                    .px_2()
 9456                                    .rounded_r(RADIUS - BORDER_WIDTH)
 9457                                    .border_l_1()
 9458                                    .border_color(cx.theme().colors().border)
 9459                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9460                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 9461                                        el.child(
 9462                                            Label::new("Hold")
 9463                                                .size(LabelSize::Small)
 9464                                                .when(accept_keystroke.is_none(), |el| {
 9465                                                    el.strikethrough()
 9466                                                })
 9467                                                .line_height_style(LineHeightStyle::UiLabel),
 9468                                        )
 9469                                    })
 9470                                    .id("edit_prediction_cursor_popover_keybind")
 9471                                    .when(accept_keystroke.is_none(), |el| {
 9472                                        let status_colors = cx.theme().status();
 9473
 9474                                        el.bg(status_colors.error_background)
 9475                                            .border_color(status_colors.error.opacity(0.6))
 9476                                            .child(Icon::new(IconName::Info).color(Color::Error))
 9477                                            .cursor_default()
 9478                                            .hoverable_tooltip(move |_window, cx| {
 9479                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 9480                                                    .into()
 9481                                            })
 9482                                    })
 9483                                    .when_some(
 9484                                        accept_keystroke.as_ref(),
 9485                                        |el, accept_keystroke| {
 9486                                            el.child(h_flex().children(ui::render_modifiers(
 9487                                                accept_keystroke.modifiers(),
 9488                                                PlatformStyle::platform(),
 9489                                                Some(Color::Default),
 9490                                                Some(IconSize::XSmall.rems().into()),
 9491                                                false,
 9492                                            )))
 9493                                        },
 9494                                    ),
 9495                            )
 9496                            .into_any(),
 9497                    );
 9498                }
 9499
 9500                self.render_edit_prediction_cursor_popover_preview(
 9501                    prediction,
 9502                    cursor_point,
 9503                    style,
 9504                    cx,
 9505                )?
 9506            }
 9507
 9508            None if is_refreshing => match &self.stale_edit_prediction_in_menu {
 9509                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 9510                    stale_completion,
 9511                    cursor_point,
 9512                    style,
 9513                    cx,
 9514                )?,
 9515
 9516                None => pending_completion_container(provider_icon)
 9517                    .child(Label::new("...").size(LabelSize::Small)),
 9518            },
 9519
 9520            None => pending_completion_container(provider_icon)
 9521                .child(Label::new("...").size(LabelSize::Small)),
 9522        };
 9523
 9524        let completion = if is_refreshing || self.active_edit_prediction.is_none() {
 9525            completion
 9526                .with_animation(
 9527                    "loading-completion",
 9528                    Animation::new(Duration::from_secs(2))
 9529                        .repeat()
 9530                        .with_easing(pulsating_between(0.4, 0.8)),
 9531                    |label, delta| label.opacity(delta),
 9532                )
 9533                .into_any_element()
 9534        } else {
 9535            completion.into_any_element()
 9536        };
 9537
 9538        let has_completion = self.active_edit_prediction.is_some();
 9539
 9540        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9541        Some(
 9542            h_flex()
 9543                .min_w(min_width)
 9544                .max_w(max_width)
 9545                .flex_1()
 9546                .elevation_2(cx)
 9547                .border_color(cx.theme().colors().border)
 9548                .child(
 9549                    div()
 9550                        .flex_1()
 9551                        .py_1()
 9552                        .px_2()
 9553                        .overflow_hidden()
 9554                        .child(completion),
 9555                )
 9556                .when_some(accept_keystroke, |el, accept_keystroke| {
 9557                    if !accept_keystroke.modifiers().modified() {
 9558                        return el;
 9559                    }
 9560
 9561                    el.child(
 9562                        h_flex()
 9563                            .h_full()
 9564                            .border_l_1()
 9565                            .rounded_r_lg()
 9566                            .border_color(cx.theme().colors().border)
 9567                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9568                            .gap_1()
 9569                            .py_1()
 9570                            .px_2()
 9571                            .child(
 9572                                h_flex()
 9573                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9574                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 9575                                    .child(h_flex().children(ui::render_modifiers(
 9576                                        accept_keystroke.modifiers(),
 9577                                        PlatformStyle::platform(),
 9578                                        Some(if !has_completion {
 9579                                            Color::Muted
 9580                                        } else {
 9581                                            Color::Default
 9582                                        }),
 9583                                        None,
 9584                                        false,
 9585                                    ))),
 9586                            )
 9587                            .child(Label::new("Preview").into_any_element())
 9588                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 9589                    )
 9590                })
 9591                .into_any(),
 9592        )
 9593    }
 9594
 9595    fn render_edit_prediction_cursor_popover_preview(
 9596        &self,
 9597        completion: &EditPredictionState,
 9598        cursor_point: Point,
 9599        style: &EditorStyle,
 9600        cx: &mut Context<Editor>,
 9601    ) -> Option<Div> {
 9602        use text::ToPoint as _;
 9603
 9604        fn render_relative_row_jump(
 9605            prefix: impl Into<String>,
 9606            current_row: u32,
 9607            target_row: u32,
 9608        ) -> Div {
 9609            let (row_diff, arrow) = if target_row < current_row {
 9610                (current_row - target_row, IconName::ArrowUp)
 9611            } else {
 9612                (target_row - current_row, IconName::ArrowDown)
 9613            };
 9614
 9615            h_flex()
 9616                .child(
 9617                    Label::new(format!("{}{}", prefix.into(), row_diff))
 9618                        .color(Color::Muted)
 9619                        .size(LabelSize::Small),
 9620                )
 9621                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 9622        }
 9623
 9624        let supports_jump = self
 9625            .edit_prediction_provider
 9626            .as_ref()
 9627            .map(|provider| provider.provider.supports_jump_to_edit())
 9628            .unwrap_or(true);
 9629
 9630        match &completion.completion {
 9631            EditPrediction::MoveWithin {
 9632                target, snapshot, ..
 9633            } => {
 9634                if !supports_jump {
 9635                    return None;
 9636                }
 9637
 9638                Some(
 9639                    h_flex()
 9640                        .px_2()
 9641                        .gap_2()
 9642                        .flex_1()
 9643                        .child(
 9644                            if target.text_anchor.to_point(snapshot).row > cursor_point.row {
 9645                                Icon::new(IconName::ZedPredictDown)
 9646                            } else {
 9647                                Icon::new(IconName::ZedPredictUp)
 9648                            },
 9649                        )
 9650                        .child(Label::new("Jump to Edit")),
 9651                )
 9652            }
 9653            EditPrediction::MoveOutside { snapshot, .. } => {
 9654                let file_name = snapshot
 9655                    .file()
 9656                    .map(|file| file.file_name(cx))
 9657                    .unwrap_or("untitled");
 9658                Some(
 9659                    h_flex()
 9660                        .px_2()
 9661                        .gap_2()
 9662                        .flex_1()
 9663                        .child(Icon::new(IconName::ZedPredict))
 9664                        .child(Label::new(format!("Jump to {file_name}"))),
 9665                )
 9666            }
 9667            EditPrediction::Edit {
 9668                edits,
 9669                edit_preview,
 9670                snapshot,
 9671                display_mode: _,
 9672            } => {
 9673                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(snapshot).row;
 9674
 9675                let (highlighted_edits, has_more_lines) =
 9676                    if let Some(edit_preview) = edit_preview.as_ref() {
 9677                        crate::edit_prediction_edit_text(snapshot, edits, edit_preview, true, cx)
 9678                            .first_line_preview()
 9679                    } else {
 9680                        crate::edit_prediction_fallback_text(edits, cx).first_line_preview()
 9681                    };
 9682
 9683                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 9684                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 9685
 9686                let preview = h_flex()
 9687                    .gap_1()
 9688                    .min_w_16()
 9689                    .child(styled_text)
 9690                    .when(has_more_lines, |parent| parent.child(""));
 9691
 9692                let left = if supports_jump && first_edit_row != cursor_point.row {
 9693                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 9694                        .into_any_element()
 9695                } else {
 9696                    let icon_name =
 9697                        Editor::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9698                    Icon::new(icon_name).into_any_element()
 9699                };
 9700
 9701                Some(
 9702                    h_flex()
 9703                        .h_full()
 9704                        .flex_1()
 9705                        .gap_2()
 9706                        .pr_1()
 9707                        .overflow_x_hidden()
 9708                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9709                        .child(left)
 9710                        .child(preview),
 9711                )
 9712            }
 9713        }
 9714    }
 9715
 9716    pub fn render_context_menu(
 9717        &self,
 9718        style: &EditorStyle,
 9719        max_height_in_lines: u32,
 9720        window: &mut Window,
 9721        cx: &mut Context<Editor>,
 9722    ) -> Option<AnyElement> {
 9723        let menu = self.context_menu.borrow();
 9724        let menu = menu.as_ref()?;
 9725        if !menu.visible() {
 9726            return None;
 9727        };
 9728        Some(menu.render(style, max_height_in_lines, window, cx))
 9729    }
 9730
 9731    fn render_context_menu_aside(
 9732        &mut self,
 9733        max_size: Size<Pixels>,
 9734        window: &mut Window,
 9735        cx: &mut Context<Editor>,
 9736    ) -> Option<AnyElement> {
 9737        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 9738            if menu.visible() {
 9739                menu.render_aside(max_size, window, cx)
 9740            } else {
 9741                None
 9742            }
 9743        })
 9744    }
 9745
 9746    fn hide_context_menu(
 9747        &mut self,
 9748        window: &mut Window,
 9749        cx: &mut Context<Self>,
 9750    ) -> Option<CodeContextMenu> {
 9751        cx.notify();
 9752        self.completion_tasks.clear();
 9753        let context_menu = self.context_menu.borrow_mut().take();
 9754        self.stale_edit_prediction_in_menu.take();
 9755        self.update_visible_edit_prediction(window, cx);
 9756        if let Some(CodeContextMenu::Completions(_)) = &context_menu
 9757            && let Some(completion_provider) = &self.completion_provider
 9758        {
 9759            completion_provider.selection_changed(None, window, cx);
 9760        }
 9761        context_menu
 9762    }
 9763
 9764    fn show_snippet_choices(
 9765        &mut self,
 9766        choices: &Vec<String>,
 9767        selection: Range<Anchor>,
 9768        cx: &mut Context<Self>,
 9769    ) {
 9770        let Some((_, buffer, _)) = self
 9771            .buffer()
 9772            .read(cx)
 9773            .excerpt_containing(selection.start, cx)
 9774        else {
 9775            return;
 9776        };
 9777        let Some((_, end_buffer, _)) = self.buffer().read(cx).excerpt_containing(selection.end, cx)
 9778        else {
 9779            return;
 9780        };
 9781        if buffer != end_buffer {
 9782            log::error!("expected anchor range to have matching buffer IDs");
 9783            return;
 9784        }
 9785
 9786        let id = post_inc(&mut self.next_completion_id);
 9787        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 9788        *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 9789            CompletionsMenu::new_snippet_choices(
 9790                id,
 9791                true,
 9792                choices,
 9793                selection,
 9794                buffer,
 9795                snippet_sort_order,
 9796            ),
 9797        ));
 9798    }
 9799
 9800    pub fn insert_snippet(
 9801        &mut self,
 9802        insertion_ranges: &[Range<usize>],
 9803        snippet: Snippet,
 9804        window: &mut Window,
 9805        cx: &mut Context<Self>,
 9806    ) -> Result<()> {
 9807        struct Tabstop<T> {
 9808            is_end_tabstop: bool,
 9809            ranges: Vec<Range<T>>,
 9810            choices: Option<Vec<String>>,
 9811        }
 9812
 9813        let tabstops = self.buffer.update(cx, |buffer, cx| {
 9814            let snippet_text: Arc<str> = snippet.text.clone().into();
 9815            let edits = insertion_ranges
 9816                .iter()
 9817                .cloned()
 9818                .map(|range| (range, snippet_text.clone()));
 9819            let autoindent_mode = AutoindentMode::Block {
 9820                original_indent_columns: Vec::new(),
 9821            };
 9822            buffer.edit(edits, Some(autoindent_mode), cx);
 9823
 9824            let snapshot = &*buffer.read(cx);
 9825            let snippet = &snippet;
 9826            snippet
 9827                .tabstops
 9828                .iter()
 9829                .map(|tabstop| {
 9830                    let is_end_tabstop = tabstop.ranges.first().is_some_and(|tabstop| {
 9831                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 9832                    });
 9833                    let mut tabstop_ranges = tabstop
 9834                        .ranges
 9835                        .iter()
 9836                        .flat_map(|tabstop_range| {
 9837                            let mut delta = 0_isize;
 9838                            insertion_ranges.iter().map(move |insertion_range| {
 9839                                let insertion_start = insertion_range.start as isize + delta;
 9840                                delta +=
 9841                                    snippet.text.len() as isize - insertion_range.len() as isize;
 9842
 9843                                let start = ((insertion_start + tabstop_range.start) as usize)
 9844                                    .min(snapshot.len());
 9845                                let end = ((insertion_start + tabstop_range.end) as usize)
 9846                                    .min(snapshot.len());
 9847                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 9848                            })
 9849                        })
 9850                        .collect::<Vec<_>>();
 9851                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 9852
 9853                    Tabstop {
 9854                        is_end_tabstop,
 9855                        ranges: tabstop_ranges,
 9856                        choices: tabstop.choices.clone(),
 9857                    }
 9858                })
 9859                .collect::<Vec<_>>()
 9860        });
 9861        if let Some(tabstop) = tabstops.first() {
 9862            self.change_selections(Default::default(), window, cx, |s| {
 9863                // Reverse order so that the first range is the newest created selection.
 9864                // Completions will use it and autoscroll will prioritize it.
 9865                s.select_ranges(tabstop.ranges.iter().rev().cloned());
 9866            });
 9867
 9868            if let Some(choices) = &tabstop.choices
 9869                && let Some(selection) = tabstop.ranges.first()
 9870            {
 9871                self.show_snippet_choices(choices, selection.clone(), cx)
 9872            }
 9873
 9874            // If we're already at the last tabstop and it's at the end of the snippet,
 9875            // we're done, we don't need to keep the state around.
 9876            if !tabstop.is_end_tabstop {
 9877                let choices = tabstops
 9878                    .iter()
 9879                    .map(|tabstop| tabstop.choices.clone())
 9880                    .collect();
 9881
 9882                let ranges = tabstops
 9883                    .into_iter()
 9884                    .map(|tabstop| tabstop.ranges)
 9885                    .collect::<Vec<_>>();
 9886
 9887                self.snippet_stack.push(SnippetState {
 9888                    active_index: 0,
 9889                    ranges,
 9890                    choices,
 9891                });
 9892            }
 9893
 9894            // Check whether the just-entered snippet ends with an auto-closable bracket.
 9895            if self.autoclose_regions.is_empty() {
 9896                let snapshot = self.buffer.read(cx).snapshot(cx);
 9897                for selection in &mut self.selections.all::<Point>(&self.display_snapshot(cx)) {
 9898                    let selection_head = selection.head();
 9899                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 9900                        continue;
 9901                    };
 9902
 9903                    let mut bracket_pair = None;
 9904                    let max_lookup_length = scope
 9905                        .brackets()
 9906                        .map(|(pair, _)| {
 9907                            pair.start
 9908                                .as_str()
 9909                                .chars()
 9910                                .count()
 9911                                .max(pair.end.as_str().chars().count())
 9912                        })
 9913                        .max();
 9914                    if let Some(max_lookup_length) = max_lookup_length {
 9915                        let next_text = snapshot
 9916                            .chars_at(selection_head)
 9917                            .take(max_lookup_length)
 9918                            .collect::<String>();
 9919                        let prev_text = snapshot
 9920                            .reversed_chars_at(selection_head)
 9921                            .take(max_lookup_length)
 9922                            .collect::<String>();
 9923
 9924                        for (pair, enabled) in scope.brackets() {
 9925                            if enabled
 9926                                && pair.close
 9927                                && prev_text.starts_with(pair.start.as_str())
 9928                                && next_text.starts_with(pair.end.as_str())
 9929                            {
 9930                                bracket_pair = Some(pair.clone());
 9931                                break;
 9932                            }
 9933                        }
 9934                    }
 9935
 9936                    if let Some(pair) = bracket_pair {
 9937                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 9938                        let autoclose_enabled =
 9939                            self.use_autoclose && snapshot_settings.use_autoclose;
 9940                        if autoclose_enabled {
 9941                            let start = snapshot.anchor_after(selection_head);
 9942                            let end = snapshot.anchor_after(selection_head);
 9943                            self.autoclose_regions.push(AutocloseRegion {
 9944                                selection_id: selection.id,
 9945                                range: start..end,
 9946                                pair,
 9947                            });
 9948                        }
 9949                    }
 9950                }
 9951            }
 9952        }
 9953        Ok(())
 9954    }
 9955
 9956    pub fn move_to_next_snippet_tabstop(
 9957        &mut self,
 9958        window: &mut Window,
 9959        cx: &mut Context<Self>,
 9960    ) -> bool {
 9961        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 9962    }
 9963
 9964    pub fn move_to_prev_snippet_tabstop(
 9965        &mut self,
 9966        window: &mut Window,
 9967        cx: &mut Context<Self>,
 9968    ) -> bool {
 9969        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 9970    }
 9971
 9972    pub fn move_to_snippet_tabstop(
 9973        &mut self,
 9974        bias: Bias,
 9975        window: &mut Window,
 9976        cx: &mut Context<Self>,
 9977    ) -> bool {
 9978        if let Some(mut snippet) = self.snippet_stack.pop() {
 9979            match bias {
 9980                Bias::Left => {
 9981                    if snippet.active_index > 0 {
 9982                        snippet.active_index -= 1;
 9983                    } else {
 9984                        self.snippet_stack.push(snippet);
 9985                        return false;
 9986                    }
 9987                }
 9988                Bias::Right => {
 9989                    if snippet.active_index + 1 < snippet.ranges.len() {
 9990                        snippet.active_index += 1;
 9991                    } else {
 9992                        self.snippet_stack.push(snippet);
 9993                        return false;
 9994                    }
 9995                }
 9996            }
 9997            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 9998                self.change_selections(Default::default(), window, cx, |s| {
 9999                    // Reverse order so that the first range is the newest created selection.
10000                    // Completions will use it and autoscroll will prioritize it.
10001                    s.select_ranges(current_ranges.iter().rev().cloned())
10002                });
10003
10004                if let Some(choices) = &snippet.choices[snippet.active_index]
10005                    && let Some(selection) = current_ranges.first()
10006                {
10007                    self.show_snippet_choices(choices, selection.clone(), cx);
10008                }
10009
10010                // If snippet state is not at the last tabstop, push it back on the stack
10011                if snippet.active_index + 1 < snippet.ranges.len() {
10012                    self.snippet_stack.push(snippet);
10013                }
10014                return true;
10015            }
10016        }
10017
10018        false
10019    }
10020
10021    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
10022        self.transact(window, cx, |this, window, cx| {
10023            this.select_all(&SelectAll, window, cx);
10024            this.insert("", window, cx);
10025        });
10026    }
10027
10028    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
10029        if self.read_only(cx) {
10030            return;
10031        }
10032        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10033        self.transact(window, cx, |this, window, cx| {
10034            this.select_autoclose_pair(window, cx);
10035
10036            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
10037
10038            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
10039            if !this.linked_edit_ranges.is_empty() {
10040                let selections = this.selections.all::<MultiBufferPoint>(&display_map);
10041                let snapshot = this.buffer.read(cx).snapshot(cx);
10042
10043                for selection in selections.iter() {
10044                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
10045                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
10046                    if selection_start.buffer_id != selection_end.buffer_id {
10047                        continue;
10048                    }
10049                    if let Some(ranges) =
10050                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
10051                    {
10052                        for (buffer, entries) in ranges {
10053                            linked_ranges.entry(buffer).or_default().extend(entries);
10054                        }
10055                    }
10056                }
10057            }
10058
10059            let mut selections = this.selections.all::<MultiBufferPoint>(&display_map);
10060            for selection in &mut selections {
10061                if selection.is_empty() {
10062                    let old_head = selection.head();
10063                    let mut new_head =
10064                        movement::left(&display_map, old_head.to_display_point(&display_map))
10065                            .to_point(&display_map);
10066                    if let Some((buffer, line_buffer_range)) = display_map
10067                        .buffer_snapshot()
10068                        .buffer_line_for_row(MultiBufferRow(old_head.row))
10069                    {
10070                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
10071                        let indent_len = match indent_size.kind {
10072                            IndentKind::Space => {
10073                                buffer.settings_at(line_buffer_range.start, cx).tab_size
10074                            }
10075                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
10076                        };
10077                        if old_head.column <= indent_size.len && old_head.column > 0 {
10078                            let indent_len = indent_len.get();
10079                            new_head = cmp::min(
10080                                new_head,
10081                                MultiBufferPoint::new(
10082                                    old_head.row,
10083                                    ((old_head.column - 1) / indent_len) * indent_len,
10084                                ),
10085                            );
10086                        }
10087                    }
10088
10089                    selection.set_head(new_head, SelectionGoal::None);
10090                }
10091            }
10092
10093            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10094            this.insert("", window, cx);
10095            let empty_str: Arc<str> = Arc::from("");
10096            for (buffer, edits) in linked_ranges {
10097                let snapshot = buffer.read(cx).snapshot();
10098                use text::ToPoint as TP;
10099
10100                let edits = edits
10101                    .into_iter()
10102                    .map(|range| {
10103                        let end_point = TP::to_point(&range.end, &snapshot);
10104                        let mut start_point = TP::to_point(&range.start, &snapshot);
10105
10106                        if end_point == start_point {
10107                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
10108                                .saturating_sub(1);
10109                            start_point =
10110                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
10111                        };
10112
10113                        (start_point..end_point, empty_str.clone())
10114                    })
10115                    .sorted_by_key(|(range, _)| range.start)
10116                    .collect::<Vec<_>>();
10117                buffer.update(cx, |this, cx| {
10118                    this.edit(edits, None, cx);
10119                })
10120            }
10121            this.refresh_edit_prediction(true, false, window, cx);
10122            refresh_linked_ranges(this, window, cx);
10123        });
10124    }
10125
10126    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
10127        if self.read_only(cx) {
10128            return;
10129        }
10130        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10131        self.transact(window, cx, |this, window, cx| {
10132            this.change_selections(Default::default(), window, cx, |s| {
10133                s.move_with(|map, selection| {
10134                    if selection.is_empty() {
10135                        let cursor = movement::right(map, selection.head());
10136                        selection.end = cursor;
10137                        selection.reversed = true;
10138                        selection.goal = SelectionGoal::None;
10139                    }
10140                })
10141            });
10142            this.insert("", window, cx);
10143            this.refresh_edit_prediction(true, false, window, cx);
10144        });
10145    }
10146
10147    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
10148        if self.mode.is_single_line() {
10149            cx.propagate();
10150            return;
10151        }
10152
10153        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10154        if self.move_to_prev_snippet_tabstop(window, cx) {
10155            return;
10156        }
10157        self.outdent(&Outdent, window, cx);
10158    }
10159
10160    pub fn next_snippet_tabstop(
10161        &mut self,
10162        _: &NextSnippetTabstop,
10163        window: &mut Window,
10164        cx: &mut Context<Self>,
10165    ) {
10166        if self.mode.is_single_line() || self.snippet_stack.is_empty() {
10167            cx.propagate();
10168            return;
10169        }
10170
10171        if self.move_to_next_snippet_tabstop(window, cx) {
10172            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10173            return;
10174        }
10175        cx.propagate();
10176    }
10177
10178    pub fn previous_snippet_tabstop(
10179        &mut self,
10180        _: &PreviousSnippetTabstop,
10181        window: &mut Window,
10182        cx: &mut Context<Self>,
10183    ) {
10184        if self.mode.is_single_line() || self.snippet_stack.is_empty() {
10185            cx.propagate();
10186            return;
10187        }
10188
10189        if self.move_to_prev_snippet_tabstop(window, cx) {
10190            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10191            return;
10192        }
10193        cx.propagate();
10194    }
10195
10196    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
10197        if self.mode.is_single_line() {
10198            cx.propagate();
10199            return;
10200        }
10201
10202        if self.move_to_next_snippet_tabstop(window, cx) {
10203            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10204            return;
10205        }
10206        if self.read_only(cx) {
10207            return;
10208        }
10209        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10210        let mut selections = self.selections.all_adjusted(&self.display_snapshot(cx));
10211        let buffer = self.buffer.read(cx);
10212        let snapshot = buffer.snapshot(cx);
10213        let rows_iter = selections.iter().map(|s| s.head().row);
10214        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
10215
10216        let has_some_cursor_in_whitespace = selections
10217            .iter()
10218            .filter(|selection| selection.is_empty())
10219            .any(|selection| {
10220                let cursor = selection.head();
10221                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10222                cursor.column < current_indent.len
10223            });
10224
10225        let mut edits = Vec::new();
10226        let mut prev_edited_row = 0;
10227        let mut row_delta = 0;
10228        for selection in &mut selections {
10229            if selection.start.row != prev_edited_row {
10230                row_delta = 0;
10231            }
10232            prev_edited_row = selection.end.row;
10233
10234            // If the selection is non-empty, then increase the indentation of the selected lines.
10235            if !selection.is_empty() {
10236                row_delta =
10237                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10238                continue;
10239            }
10240
10241            let cursor = selection.head();
10242            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10243            if let Some(suggested_indent) =
10244                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
10245            {
10246                // Don't do anything if already at suggested indent
10247                // and there is any other cursor which is not
10248                if has_some_cursor_in_whitespace
10249                    && cursor.column == current_indent.len
10250                    && current_indent.len == suggested_indent.len
10251                {
10252                    continue;
10253                }
10254
10255                // Adjust line and move cursor to suggested indent
10256                // if cursor is not at suggested indent
10257                if cursor.column < suggested_indent.len
10258                    && cursor.column <= current_indent.len
10259                    && current_indent.len <= suggested_indent.len
10260                {
10261                    selection.start = Point::new(cursor.row, suggested_indent.len);
10262                    selection.end = selection.start;
10263                    if row_delta == 0 {
10264                        edits.extend(Buffer::edit_for_indent_size_adjustment(
10265                            cursor.row,
10266                            current_indent,
10267                            suggested_indent,
10268                        ));
10269                        row_delta = suggested_indent.len - current_indent.len;
10270                    }
10271                    continue;
10272                }
10273
10274                // If current indent is more than suggested indent
10275                // only move cursor to current indent and skip indent
10276                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
10277                    selection.start = Point::new(cursor.row, current_indent.len);
10278                    selection.end = selection.start;
10279                    continue;
10280                }
10281            }
10282
10283            // Otherwise, insert a hard or soft tab.
10284            let settings = buffer.language_settings_at(cursor, cx);
10285            let tab_size = if settings.hard_tabs {
10286                IndentSize::tab()
10287            } else {
10288                let tab_size = settings.tab_size.get();
10289                let indent_remainder = snapshot
10290                    .text_for_range(Point::new(cursor.row, 0)..cursor)
10291                    .flat_map(str::chars)
10292                    .fold(row_delta % tab_size, |counter: u32, c| {
10293                        if c == '\t' {
10294                            0
10295                        } else {
10296                            (counter + 1) % tab_size
10297                        }
10298                    });
10299
10300                let chars_to_next_tab_stop = tab_size - indent_remainder;
10301                IndentSize::spaces(chars_to_next_tab_stop)
10302            };
10303            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
10304            selection.end = selection.start;
10305            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
10306            row_delta += tab_size.len;
10307        }
10308
10309        self.transact(window, cx, |this, window, cx| {
10310            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10311            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10312            this.refresh_edit_prediction(true, false, window, cx);
10313        });
10314    }
10315
10316    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
10317        if self.read_only(cx) {
10318            return;
10319        }
10320        if self.mode.is_single_line() {
10321            cx.propagate();
10322            return;
10323        }
10324
10325        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10326        let mut selections = self.selections.all::<Point>(&self.display_snapshot(cx));
10327        let mut prev_edited_row = 0;
10328        let mut row_delta = 0;
10329        let mut edits = Vec::new();
10330        let buffer = self.buffer.read(cx);
10331        let snapshot = buffer.snapshot(cx);
10332        for selection in &mut selections {
10333            if selection.start.row != prev_edited_row {
10334                row_delta = 0;
10335            }
10336            prev_edited_row = selection.end.row;
10337
10338            row_delta =
10339                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10340        }
10341
10342        self.transact(window, cx, |this, window, cx| {
10343            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10344            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10345        });
10346    }
10347
10348    fn indent_selection(
10349        buffer: &MultiBuffer,
10350        snapshot: &MultiBufferSnapshot,
10351        selection: &mut Selection<Point>,
10352        edits: &mut Vec<(Range<Point>, String)>,
10353        delta_for_start_row: u32,
10354        cx: &App,
10355    ) -> u32 {
10356        let settings = buffer.language_settings_at(selection.start, cx);
10357        let tab_size = settings.tab_size.get();
10358        let indent_kind = if settings.hard_tabs {
10359            IndentKind::Tab
10360        } else {
10361            IndentKind::Space
10362        };
10363        let mut start_row = selection.start.row;
10364        let mut end_row = selection.end.row + 1;
10365
10366        // If a selection ends at the beginning of a line, don't indent
10367        // that last line.
10368        if selection.end.column == 0 && selection.end.row > selection.start.row {
10369            end_row -= 1;
10370        }
10371
10372        // Avoid re-indenting a row that has already been indented by a
10373        // previous selection, but still update this selection's column
10374        // to reflect that indentation.
10375        if delta_for_start_row > 0 {
10376            start_row += 1;
10377            selection.start.column += delta_for_start_row;
10378            if selection.end.row == selection.start.row {
10379                selection.end.column += delta_for_start_row;
10380            }
10381        }
10382
10383        let mut delta_for_end_row = 0;
10384        let has_multiple_rows = start_row + 1 != end_row;
10385        for row in start_row..end_row {
10386            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
10387            let indent_delta = match (current_indent.kind, indent_kind) {
10388                (IndentKind::Space, IndentKind::Space) => {
10389                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
10390                    IndentSize::spaces(columns_to_next_tab_stop)
10391                }
10392                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
10393                (_, IndentKind::Tab) => IndentSize::tab(),
10394            };
10395
10396            let start = if has_multiple_rows || current_indent.len < selection.start.column {
10397                0
10398            } else {
10399                selection.start.column
10400            };
10401            let row_start = Point::new(row, start);
10402            edits.push((
10403                row_start..row_start,
10404                indent_delta.chars().collect::<String>(),
10405            ));
10406
10407            // Update this selection's endpoints to reflect the indentation.
10408            if row == selection.start.row {
10409                selection.start.column += indent_delta.len;
10410            }
10411            if row == selection.end.row {
10412                selection.end.column += indent_delta.len;
10413                delta_for_end_row = indent_delta.len;
10414            }
10415        }
10416
10417        if selection.start.row == selection.end.row {
10418            delta_for_start_row + delta_for_end_row
10419        } else {
10420            delta_for_end_row
10421        }
10422    }
10423
10424    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
10425        if self.read_only(cx) {
10426            return;
10427        }
10428        if self.mode.is_single_line() {
10429            cx.propagate();
10430            return;
10431        }
10432
10433        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10434        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10435        let selections = self.selections.all::<Point>(&display_map);
10436        let mut deletion_ranges = Vec::new();
10437        let mut last_outdent = None;
10438        {
10439            let buffer = self.buffer.read(cx);
10440            let snapshot = buffer.snapshot(cx);
10441            for selection in &selections {
10442                let settings = buffer.language_settings_at(selection.start, cx);
10443                let tab_size = settings.tab_size.get();
10444                let mut rows = selection.spanned_rows(false, &display_map);
10445
10446                // Avoid re-outdenting a row that has already been outdented by a
10447                // previous selection.
10448                if let Some(last_row) = last_outdent
10449                    && last_row == rows.start
10450                {
10451                    rows.start = rows.start.next_row();
10452                }
10453                let has_multiple_rows = rows.len() > 1;
10454                for row in rows.iter_rows() {
10455                    let indent_size = snapshot.indent_size_for_line(row);
10456                    if indent_size.len > 0 {
10457                        let deletion_len = match indent_size.kind {
10458                            IndentKind::Space => {
10459                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
10460                                if columns_to_prev_tab_stop == 0 {
10461                                    tab_size
10462                                } else {
10463                                    columns_to_prev_tab_stop
10464                                }
10465                            }
10466                            IndentKind::Tab => 1,
10467                        };
10468                        let start = if has_multiple_rows
10469                            || deletion_len > selection.start.column
10470                            || indent_size.len < selection.start.column
10471                        {
10472                            0
10473                        } else {
10474                            selection.start.column - deletion_len
10475                        };
10476                        deletion_ranges.push(
10477                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
10478                        );
10479                        last_outdent = Some(row);
10480                    }
10481                }
10482            }
10483        }
10484
10485        self.transact(window, cx, |this, window, cx| {
10486            this.buffer.update(cx, |buffer, cx| {
10487                let empty_str: Arc<str> = Arc::default();
10488                buffer.edit(
10489                    deletion_ranges
10490                        .into_iter()
10491                        .map(|range| (range, empty_str.clone())),
10492                    None,
10493                    cx,
10494                );
10495            });
10496            let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
10497            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10498        });
10499    }
10500
10501    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
10502        if self.read_only(cx) {
10503            return;
10504        }
10505        if self.mode.is_single_line() {
10506            cx.propagate();
10507            return;
10508        }
10509
10510        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10511        let selections = self
10512            .selections
10513            .all::<usize>(&self.display_snapshot(cx))
10514            .into_iter()
10515            .map(|s| s.range());
10516
10517        self.transact(window, cx, |this, window, cx| {
10518            this.buffer.update(cx, |buffer, cx| {
10519                buffer.autoindent_ranges(selections, cx);
10520            });
10521            let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
10522            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10523        });
10524    }
10525
10526    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
10527        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10528        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10529        let selections = self.selections.all::<Point>(&display_map);
10530
10531        let mut new_cursors = Vec::new();
10532        let mut edit_ranges = Vec::new();
10533        let mut selections = selections.iter().peekable();
10534        while let Some(selection) = selections.next() {
10535            let mut rows = selection.spanned_rows(false, &display_map);
10536
10537            // Accumulate contiguous regions of rows that we want to delete.
10538            while let Some(next_selection) = selections.peek() {
10539                let next_rows = next_selection.spanned_rows(false, &display_map);
10540                if next_rows.start <= rows.end {
10541                    rows.end = next_rows.end;
10542                    selections.next().unwrap();
10543                } else {
10544                    break;
10545                }
10546            }
10547
10548            let buffer = display_map.buffer_snapshot();
10549            let mut edit_start = ToOffset::to_offset(&Point::new(rows.start.0, 0), buffer);
10550            let (edit_end, target_row) = if buffer.max_point().row >= rows.end.0 {
10551                // If there's a line after the range, delete the \n from the end of the row range
10552                (
10553                    ToOffset::to_offset(&Point::new(rows.end.0, 0), buffer),
10554                    rows.end,
10555                )
10556            } else {
10557                // If there isn't a line after the range, delete the \n from the line before the
10558                // start of the row range
10559                edit_start = edit_start.saturating_sub(1);
10560                (buffer.len(), rows.start.previous_row())
10561            };
10562
10563            let text_layout_details = self.text_layout_details(window);
10564            let x = display_map.x_for_display_point(
10565                selection.head().to_display_point(&display_map),
10566                &text_layout_details,
10567            );
10568            let row = Point::new(target_row.0, 0)
10569                .to_display_point(&display_map)
10570                .row();
10571            let column = display_map.display_column_for_x(row, x, &text_layout_details);
10572
10573            new_cursors.push((
10574                selection.id,
10575                buffer.anchor_after(DisplayPoint::new(row, column).to_point(&display_map)),
10576                SelectionGoal::None,
10577            ));
10578            edit_ranges.push(edit_start..edit_end);
10579        }
10580
10581        self.transact(window, cx, |this, window, cx| {
10582            let buffer = this.buffer.update(cx, |buffer, cx| {
10583                let empty_str: Arc<str> = Arc::default();
10584                buffer.edit(
10585                    edit_ranges
10586                        .into_iter()
10587                        .map(|range| (range, empty_str.clone())),
10588                    None,
10589                    cx,
10590                );
10591                buffer.snapshot(cx)
10592            });
10593            let new_selections = new_cursors
10594                .into_iter()
10595                .map(|(id, cursor, goal)| {
10596                    let cursor = cursor.to_point(&buffer);
10597                    Selection {
10598                        id,
10599                        start: cursor,
10600                        end: cursor,
10601                        reversed: false,
10602                        goal,
10603                    }
10604                })
10605                .collect();
10606
10607            this.change_selections(Default::default(), window, cx, |s| {
10608                s.select(new_selections);
10609            });
10610        });
10611    }
10612
10613    pub fn join_lines_impl(
10614        &mut self,
10615        insert_whitespace: bool,
10616        window: &mut Window,
10617        cx: &mut Context<Self>,
10618    ) {
10619        if self.read_only(cx) {
10620            return;
10621        }
10622        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
10623        for selection in self.selections.all::<Point>(&self.display_snapshot(cx)) {
10624            let start = MultiBufferRow(selection.start.row);
10625            // Treat single line selections as if they include the next line. Otherwise this action
10626            // would do nothing for single line selections individual cursors.
10627            let end = if selection.start.row == selection.end.row {
10628                MultiBufferRow(selection.start.row + 1)
10629            } else {
10630                MultiBufferRow(selection.end.row)
10631            };
10632
10633            if let Some(last_row_range) = row_ranges.last_mut()
10634                && start <= last_row_range.end
10635            {
10636                last_row_range.end = end;
10637                continue;
10638            }
10639            row_ranges.push(start..end);
10640        }
10641
10642        let snapshot = self.buffer.read(cx).snapshot(cx);
10643        let mut cursor_positions = Vec::new();
10644        for row_range in &row_ranges {
10645            let anchor = snapshot.anchor_before(Point::new(
10646                row_range.end.previous_row().0,
10647                snapshot.line_len(row_range.end.previous_row()),
10648            ));
10649            cursor_positions.push(anchor..anchor);
10650        }
10651
10652        self.transact(window, cx, |this, window, cx| {
10653            for row_range in row_ranges.into_iter().rev() {
10654                for row in row_range.iter_rows().rev() {
10655                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
10656                    let next_line_row = row.next_row();
10657                    let indent = snapshot.indent_size_for_line(next_line_row);
10658                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
10659
10660                    let replace =
10661                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
10662                            " "
10663                        } else {
10664                            ""
10665                        };
10666
10667                    this.buffer.update(cx, |buffer, cx| {
10668                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
10669                    });
10670                }
10671            }
10672
10673            this.change_selections(Default::default(), window, cx, |s| {
10674                s.select_anchor_ranges(cursor_positions)
10675            });
10676        });
10677    }
10678
10679    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
10680        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10681        self.join_lines_impl(true, window, cx);
10682    }
10683
10684    pub fn sort_lines_case_sensitive(
10685        &mut self,
10686        _: &SortLinesCaseSensitive,
10687        window: &mut Window,
10688        cx: &mut Context<Self>,
10689    ) {
10690        self.manipulate_immutable_lines(window, cx, |lines| lines.sort())
10691    }
10692
10693    pub fn sort_lines_by_length(
10694        &mut self,
10695        _: &SortLinesByLength,
10696        window: &mut Window,
10697        cx: &mut Context<Self>,
10698    ) {
10699        self.manipulate_immutable_lines(window, cx, |lines| {
10700            lines.sort_by_key(|&line| line.chars().count())
10701        })
10702    }
10703
10704    pub fn sort_lines_case_insensitive(
10705        &mut self,
10706        _: &SortLinesCaseInsensitive,
10707        window: &mut Window,
10708        cx: &mut Context<Self>,
10709    ) {
10710        self.manipulate_immutable_lines(window, cx, |lines| {
10711            lines.sort_by_key(|line| line.to_lowercase())
10712        })
10713    }
10714
10715    pub fn unique_lines_case_insensitive(
10716        &mut self,
10717        _: &UniqueLinesCaseInsensitive,
10718        window: &mut Window,
10719        cx: &mut Context<Self>,
10720    ) {
10721        self.manipulate_immutable_lines(window, cx, |lines| {
10722            let mut seen = HashSet::default();
10723            lines.retain(|line| seen.insert(line.to_lowercase()));
10724        })
10725    }
10726
10727    pub fn unique_lines_case_sensitive(
10728        &mut self,
10729        _: &UniqueLinesCaseSensitive,
10730        window: &mut Window,
10731        cx: &mut Context<Self>,
10732    ) {
10733        self.manipulate_immutable_lines(window, cx, |lines| {
10734            let mut seen = HashSet::default();
10735            lines.retain(|line| seen.insert(*line));
10736        })
10737    }
10738
10739    fn enable_wrap_selections_in_tag(&self, cx: &App) -> bool {
10740        let snapshot = self.buffer.read(cx).snapshot(cx);
10741        for selection in self.selections.disjoint_anchors_arc().iter() {
10742            if snapshot
10743                .language_at(selection.start)
10744                .and_then(|lang| lang.config().wrap_characters.as_ref())
10745                .is_some()
10746            {
10747                return true;
10748            }
10749        }
10750        false
10751    }
10752
10753    fn wrap_selections_in_tag(
10754        &mut self,
10755        _: &WrapSelectionsInTag,
10756        window: &mut Window,
10757        cx: &mut Context<Self>,
10758    ) {
10759        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10760
10761        let snapshot = self.buffer.read(cx).snapshot(cx);
10762
10763        let mut edits = Vec::new();
10764        let mut boundaries = Vec::new();
10765
10766        for selection in self
10767            .selections
10768            .all_adjusted(&self.display_snapshot(cx))
10769            .iter()
10770        {
10771            let Some(wrap_config) = snapshot
10772                .language_at(selection.start)
10773                .and_then(|lang| lang.config().wrap_characters.clone())
10774            else {
10775                continue;
10776            };
10777
10778            let open_tag = format!("{}{}", wrap_config.start_prefix, wrap_config.start_suffix);
10779            let close_tag = format!("{}{}", wrap_config.end_prefix, wrap_config.end_suffix);
10780
10781            let start_before = snapshot.anchor_before(selection.start);
10782            let end_after = snapshot.anchor_after(selection.end);
10783
10784            edits.push((start_before..start_before, open_tag));
10785            edits.push((end_after..end_after, close_tag));
10786
10787            boundaries.push((
10788                start_before,
10789                end_after,
10790                wrap_config.start_prefix.len(),
10791                wrap_config.end_suffix.len(),
10792            ));
10793        }
10794
10795        if edits.is_empty() {
10796            return;
10797        }
10798
10799        self.transact(window, cx, |this, window, cx| {
10800            let buffer = this.buffer.update(cx, |buffer, cx| {
10801                buffer.edit(edits, None, cx);
10802                buffer.snapshot(cx)
10803            });
10804
10805            let mut new_selections = Vec::with_capacity(boundaries.len() * 2);
10806            for (start_before, end_after, start_prefix_len, end_suffix_len) in
10807                boundaries.into_iter()
10808            {
10809                let open_offset = start_before.to_offset(&buffer) + start_prefix_len;
10810                let close_offset = end_after.to_offset(&buffer).saturating_sub(end_suffix_len);
10811                new_selections.push(open_offset..open_offset);
10812                new_selections.push(close_offset..close_offset);
10813            }
10814
10815            this.change_selections(Default::default(), window, cx, |s| {
10816                s.select_ranges(new_selections);
10817            });
10818
10819            this.request_autoscroll(Autoscroll::fit(), cx);
10820        });
10821    }
10822
10823    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
10824        let Some(project) = self.project.clone() else {
10825            return;
10826        };
10827        self.reload(project, window, cx)
10828            .detach_and_notify_err(window, cx);
10829    }
10830
10831    pub fn restore_file(
10832        &mut self,
10833        _: &::git::RestoreFile,
10834        window: &mut Window,
10835        cx: &mut Context<Self>,
10836    ) {
10837        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10838        let mut buffer_ids = HashSet::default();
10839        let snapshot = self.buffer().read(cx).snapshot(cx);
10840        for selection in self.selections.all::<usize>(&self.display_snapshot(cx)) {
10841            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
10842        }
10843
10844        let buffer = self.buffer().read(cx);
10845        let ranges = buffer_ids
10846            .into_iter()
10847            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
10848            .collect::<Vec<_>>();
10849
10850        self.restore_hunks_in_ranges(ranges, window, cx);
10851    }
10852
10853    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
10854        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10855        let selections = self
10856            .selections
10857            .all(&self.display_snapshot(cx))
10858            .into_iter()
10859            .map(|s| s.range())
10860            .collect();
10861        self.restore_hunks_in_ranges(selections, window, cx);
10862    }
10863
10864    pub fn restore_hunks_in_ranges(
10865        &mut self,
10866        ranges: Vec<Range<Point>>,
10867        window: &mut Window,
10868        cx: &mut Context<Editor>,
10869    ) {
10870        let mut revert_changes = HashMap::default();
10871        let chunk_by = self
10872            .snapshot(window, cx)
10873            .hunks_for_ranges(ranges)
10874            .into_iter()
10875            .chunk_by(|hunk| hunk.buffer_id);
10876        for (buffer_id, hunks) in &chunk_by {
10877            let hunks = hunks.collect::<Vec<_>>();
10878            for hunk in &hunks {
10879                self.prepare_restore_change(&mut revert_changes, hunk, cx);
10880            }
10881            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
10882        }
10883        drop(chunk_by);
10884        if !revert_changes.is_empty() {
10885            self.transact(window, cx, |editor, window, cx| {
10886                editor.restore(revert_changes, window, cx);
10887            });
10888        }
10889    }
10890
10891    pub fn status_for_buffer_id(&self, buffer_id: BufferId, cx: &App) -> Option<FileStatus> {
10892        if let Some(status) = self
10893            .addons
10894            .iter()
10895            .find_map(|(_, addon)| addon.override_status_for_buffer_id(buffer_id, cx))
10896        {
10897            return Some(status);
10898        }
10899        self.project
10900            .as_ref()?
10901            .read(cx)
10902            .status_for_buffer_id(buffer_id, cx)
10903    }
10904
10905    pub fn open_active_item_in_terminal(
10906        &mut self,
10907        _: &OpenInTerminal,
10908        window: &mut Window,
10909        cx: &mut Context<Self>,
10910    ) {
10911        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
10912            let project_path = buffer.read(cx).project_path(cx)?;
10913            let project = self.project()?.read(cx);
10914            let entry = project.entry_for_path(&project_path, cx)?;
10915            let parent = match &entry.canonical_path {
10916                Some(canonical_path) => canonical_path.to_path_buf(),
10917                None => project.absolute_path(&project_path, cx)?,
10918            }
10919            .parent()?
10920            .to_path_buf();
10921            Some(parent)
10922        }) {
10923            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
10924        }
10925    }
10926
10927    fn set_breakpoint_context_menu(
10928        &mut self,
10929        display_row: DisplayRow,
10930        position: Option<Anchor>,
10931        clicked_point: gpui::Point<Pixels>,
10932        window: &mut Window,
10933        cx: &mut Context<Self>,
10934    ) {
10935        let source = self
10936            .buffer
10937            .read(cx)
10938            .snapshot(cx)
10939            .anchor_before(Point::new(display_row.0, 0u32));
10940
10941        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
10942
10943        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
10944            self,
10945            source,
10946            clicked_point,
10947            context_menu,
10948            window,
10949            cx,
10950        );
10951    }
10952
10953    fn add_edit_breakpoint_block(
10954        &mut self,
10955        anchor: Anchor,
10956        breakpoint: &Breakpoint,
10957        edit_action: BreakpointPromptEditAction,
10958        window: &mut Window,
10959        cx: &mut Context<Self>,
10960    ) {
10961        let weak_editor = cx.weak_entity();
10962        let bp_prompt = cx.new(|cx| {
10963            BreakpointPromptEditor::new(
10964                weak_editor,
10965                anchor,
10966                breakpoint.clone(),
10967                edit_action,
10968                window,
10969                cx,
10970            )
10971        });
10972
10973        let height = bp_prompt.update(cx, |this, cx| {
10974            this.prompt
10975                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
10976        });
10977        let cloned_prompt = bp_prompt.clone();
10978        let blocks = vec![BlockProperties {
10979            style: BlockStyle::Sticky,
10980            placement: BlockPlacement::Above(anchor),
10981            height: Some(height),
10982            render: Arc::new(move |cx| {
10983                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
10984                cloned_prompt.clone().into_any_element()
10985            }),
10986            priority: 0,
10987        }];
10988
10989        let focus_handle = bp_prompt.focus_handle(cx);
10990        window.focus(&focus_handle);
10991
10992        let block_ids = self.insert_blocks(blocks, None, cx);
10993        bp_prompt.update(cx, |prompt, _| {
10994            prompt.add_block_ids(block_ids);
10995        });
10996    }
10997
10998    pub(crate) fn breakpoint_at_row(
10999        &self,
11000        row: u32,
11001        window: &mut Window,
11002        cx: &mut Context<Self>,
11003    ) -> Option<(Anchor, Breakpoint)> {
11004        let snapshot = self.snapshot(window, cx);
11005        let breakpoint_position = snapshot.buffer_snapshot().anchor_before(Point::new(row, 0));
11006
11007        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
11008    }
11009
11010    pub(crate) fn breakpoint_at_anchor(
11011        &self,
11012        breakpoint_position: Anchor,
11013        snapshot: &EditorSnapshot,
11014        cx: &mut Context<Self>,
11015    ) -> Option<(Anchor, Breakpoint)> {
11016        let buffer = self
11017            .buffer
11018            .read(cx)
11019            .buffer_for_anchor(breakpoint_position, cx)?;
11020
11021        let enclosing_excerpt = breakpoint_position.excerpt_id;
11022        let buffer_snapshot = buffer.read(cx).snapshot();
11023
11024        let row = buffer_snapshot
11025            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
11026            .row;
11027
11028        let line_len = snapshot.buffer_snapshot().line_len(MultiBufferRow(row));
11029        let anchor_end = snapshot
11030            .buffer_snapshot()
11031            .anchor_after(Point::new(row, line_len));
11032
11033        self.breakpoint_store
11034            .as_ref()?
11035            .read_with(cx, |breakpoint_store, cx| {
11036                breakpoint_store
11037                    .breakpoints(
11038                        &buffer,
11039                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
11040                        &buffer_snapshot,
11041                        cx,
11042                    )
11043                    .next()
11044                    .and_then(|(bp, _)| {
11045                        let breakpoint_row = buffer_snapshot
11046                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
11047                            .row;
11048
11049                        if breakpoint_row == row {
11050                            snapshot
11051                                .buffer_snapshot()
11052                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
11053                                .map(|position| (position, bp.bp.clone()))
11054                        } else {
11055                            None
11056                        }
11057                    })
11058            })
11059    }
11060
11061    pub fn edit_log_breakpoint(
11062        &mut self,
11063        _: &EditLogBreakpoint,
11064        window: &mut Window,
11065        cx: &mut Context<Self>,
11066    ) {
11067        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11068            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
11069                message: None,
11070                state: BreakpointState::Enabled,
11071                condition: None,
11072                hit_condition: None,
11073            });
11074
11075            self.add_edit_breakpoint_block(
11076                anchor,
11077                &breakpoint,
11078                BreakpointPromptEditAction::Log,
11079                window,
11080                cx,
11081            );
11082        }
11083    }
11084
11085    fn breakpoints_at_cursors(
11086        &self,
11087        window: &mut Window,
11088        cx: &mut Context<Self>,
11089    ) -> Vec<(Anchor, Option<Breakpoint>)> {
11090        let snapshot = self.snapshot(window, cx);
11091        let cursors = self
11092            .selections
11093            .disjoint_anchors_arc()
11094            .iter()
11095            .map(|selection| {
11096                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot());
11097
11098                let breakpoint_position = self
11099                    .breakpoint_at_row(cursor_position.row, window, cx)
11100                    .map(|bp| bp.0)
11101                    .unwrap_or_else(|| {
11102                        snapshot
11103                            .display_snapshot
11104                            .buffer_snapshot()
11105                            .anchor_after(Point::new(cursor_position.row, 0))
11106                    });
11107
11108                let breakpoint = self
11109                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
11110                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
11111
11112                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
11113            })
11114            // 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.
11115            .collect::<HashMap<Anchor, _>>();
11116
11117        cursors.into_iter().collect()
11118    }
11119
11120    pub fn enable_breakpoint(
11121        &mut self,
11122        _: &crate::actions::EnableBreakpoint,
11123        window: &mut Window,
11124        cx: &mut Context<Self>,
11125    ) {
11126        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11127            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
11128                continue;
11129            };
11130            self.edit_breakpoint_at_anchor(
11131                anchor,
11132                breakpoint,
11133                BreakpointEditAction::InvertState,
11134                cx,
11135            );
11136        }
11137    }
11138
11139    pub fn disable_breakpoint(
11140        &mut self,
11141        _: &crate::actions::DisableBreakpoint,
11142        window: &mut Window,
11143        cx: &mut Context<Self>,
11144    ) {
11145        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11146            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
11147                continue;
11148            };
11149            self.edit_breakpoint_at_anchor(
11150                anchor,
11151                breakpoint,
11152                BreakpointEditAction::InvertState,
11153                cx,
11154            );
11155        }
11156    }
11157
11158    pub fn toggle_breakpoint(
11159        &mut self,
11160        _: &crate::actions::ToggleBreakpoint,
11161        window: &mut Window,
11162        cx: &mut Context<Self>,
11163    ) {
11164        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11165            if let Some(breakpoint) = breakpoint {
11166                self.edit_breakpoint_at_anchor(
11167                    anchor,
11168                    breakpoint,
11169                    BreakpointEditAction::Toggle,
11170                    cx,
11171                );
11172            } else {
11173                self.edit_breakpoint_at_anchor(
11174                    anchor,
11175                    Breakpoint::new_standard(),
11176                    BreakpointEditAction::Toggle,
11177                    cx,
11178                );
11179            }
11180        }
11181    }
11182
11183    pub fn edit_breakpoint_at_anchor(
11184        &mut self,
11185        breakpoint_position: Anchor,
11186        breakpoint: Breakpoint,
11187        edit_action: BreakpointEditAction,
11188        cx: &mut Context<Self>,
11189    ) {
11190        let Some(breakpoint_store) = &self.breakpoint_store else {
11191            return;
11192        };
11193
11194        let Some(buffer) = self
11195            .buffer
11196            .read(cx)
11197            .buffer_for_anchor(breakpoint_position, cx)
11198        else {
11199            return;
11200        };
11201
11202        breakpoint_store.update(cx, |breakpoint_store, cx| {
11203            breakpoint_store.toggle_breakpoint(
11204                buffer,
11205                BreakpointWithPosition {
11206                    position: breakpoint_position.text_anchor,
11207                    bp: breakpoint,
11208                },
11209                edit_action,
11210                cx,
11211            );
11212        });
11213
11214        cx.notify();
11215    }
11216
11217    #[cfg(any(test, feature = "test-support"))]
11218    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
11219        self.breakpoint_store.clone()
11220    }
11221
11222    pub fn prepare_restore_change(
11223        &self,
11224        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
11225        hunk: &MultiBufferDiffHunk,
11226        cx: &mut App,
11227    ) -> Option<()> {
11228        if hunk.is_created_file() {
11229            return None;
11230        }
11231        let buffer = self.buffer.read(cx);
11232        let diff = buffer.diff_for(hunk.buffer_id)?;
11233        let buffer = buffer.buffer(hunk.buffer_id)?;
11234        let buffer = buffer.read(cx);
11235        let original_text = diff
11236            .read(cx)
11237            .base_text()
11238            .as_rope()
11239            .slice(hunk.diff_base_byte_range.clone());
11240        let buffer_snapshot = buffer.snapshot();
11241        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
11242        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
11243            probe
11244                .0
11245                .start
11246                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
11247                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
11248        }) {
11249            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
11250            Some(())
11251        } else {
11252            None
11253        }
11254    }
11255
11256    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
11257        self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())
11258    }
11259
11260    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
11261        self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut rand::rng()))
11262    }
11263
11264    fn manipulate_lines<M>(
11265        &mut self,
11266        window: &mut Window,
11267        cx: &mut Context<Self>,
11268        mut manipulate: M,
11269    ) where
11270        M: FnMut(&str) -> LineManipulationResult,
11271    {
11272        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11273
11274        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11275        let buffer = self.buffer.read(cx).snapshot(cx);
11276
11277        let mut edits = Vec::new();
11278
11279        let selections = self.selections.all::<Point>(&display_map);
11280        let mut selections = selections.iter().peekable();
11281        let mut contiguous_row_selections = Vec::new();
11282        let mut new_selections = Vec::new();
11283        let mut added_lines = 0;
11284        let mut removed_lines = 0;
11285
11286        while let Some(selection) = selections.next() {
11287            let (start_row, end_row) = consume_contiguous_rows(
11288                &mut contiguous_row_selections,
11289                selection,
11290                &display_map,
11291                &mut selections,
11292            );
11293
11294            let start_point = Point::new(start_row.0, 0);
11295            let end_point = Point::new(
11296                end_row.previous_row().0,
11297                buffer.line_len(end_row.previous_row()),
11298            );
11299            let text = buffer
11300                .text_for_range(start_point..end_point)
11301                .collect::<String>();
11302
11303            let LineManipulationResult {
11304                new_text,
11305                line_count_before,
11306                line_count_after,
11307            } = manipulate(&text);
11308
11309            edits.push((start_point..end_point, new_text));
11310
11311            // Selections must change based on added and removed line count
11312            let start_row =
11313                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
11314            let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);
11315            new_selections.push(Selection {
11316                id: selection.id,
11317                start: start_row,
11318                end: end_row,
11319                goal: SelectionGoal::None,
11320                reversed: selection.reversed,
11321            });
11322
11323            if line_count_after > line_count_before {
11324                added_lines += line_count_after - line_count_before;
11325            } else if line_count_before > line_count_after {
11326                removed_lines += line_count_before - line_count_after;
11327            }
11328        }
11329
11330        self.transact(window, cx, |this, window, cx| {
11331            let buffer = this.buffer.update(cx, |buffer, cx| {
11332                buffer.edit(edits, None, cx);
11333                buffer.snapshot(cx)
11334            });
11335
11336            // Recalculate offsets on newly edited buffer
11337            let new_selections = new_selections
11338                .iter()
11339                .map(|s| {
11340                    let start_point = Point::new(s.start.0, 0);
11341                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
11342                    Selection {
11343                        id: s.id,
11344                        start: buffer.point_to_offset(start_point),
11345                        end: buffer.point_to_offset(end_point),
11346                        goal: s.goal,
11347                        reversed: s.reversed,
11348                    }
11349                })
11350                .collect();
11351
11352            this.change_selections(Default::default(), window, cx, |s| {
11353                s.select(new_selections);
11354            });
11355
11356            this.request_autoscroll(Autoscroll::fit(), cx);
11357        });
11358    }
11359
11360    fn manipulate_immutable_lines<Fn>(
11361        &mut self,
11362        window: &mut Window,
11363        cx: &mut Context<Self>,
11364        mut callback: Fn,
11365    ) where
11366        Fn: FnMut(&mut Vec<&str>),
11367    {
11368        self.manipulate_lines(window, cx, |text| {
11369            let mut lines: Vec<&str> = text.split('\n').collect();
11370            let line_count_before = lines.len();
11371
11372            callback(&mut lines);
11373
11374            LineManipulationResult {
11375                new_text: lines.join("\n"),
11376                line_count_before,
11377                line_count_after: lines.len(),
11378            }
11379        });
11380    }
11381
11382    fn manipulate_mutable_lines<Fn>(
11383        &mut self,
11384        window: &mut Window,
11385        cx: &mut Context<Self>,
11386        mut callback: Fn,
11387    ) where
11388        Fn: FnMut(&mut Vec<Cow<'_, str>>),
11389    {
11390        self.manipulate_lines(window, cx, |text| {
11391            let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
11392            let line_count_before = lines.len();
11393
11394            callback(&mut lines);
11395
11396            LineManipulationResult {
11397                new_text: lines.join("\n"),
11398                line_count_before,
11399                line_count_after: lines.len(),
11400            }
11401        });
11402    }
11403
11404    pub fn convert_indentation_to_spaces(
11405        &mut self,
11406        _: &ConvertIndentationToSpaces,
11407        window: &mut Window,
11408        cx: &mut Context<Self>,
11409    ) {
11410        let settings = self.buffer.read(cx).language_settings(cx);
11411        let tab_size = settings.tab_size.get() as usize;
11412
11413        self.manipulate_mutable_lines(window, cx, |lines| {
11414            // Allocates a reasonably sized scratch buffer once for the whole loop
11415            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11416            // Avoids recomputing spaces that could be inserted many times
11417            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11418                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11419                .collect();
11420
11421            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11422                let mut chars = line.as_ref().chars();
11423                let mut col = 0;
11424                let mut changed = false;
11425
11426                for ch in chars.by_ref() {
11427                    match ch {
11428                        ' ' => {
11429                            reindented_line.push(' ');
11430                            col += 1;
11431                        }
11432                        '\t' => {
11433                            // \t are converted to spaces depending on the current column
11434                            let spaces_len = tab_size - (col % tab_size);
11435                            reindented_line.extend(&space_cache[spaces_len - 1]);
11436                            col += spaces_len;
11437                            changed = true;
11438                        }
11439                        _ => {
11440                            // If we dont append before break, the character is consumed
11441                            reindented_line.push(ch);
11442                            break;
11443                        }
11444                    }
11445                }
11446
11447                if !changed {
11448                    reindented_line.clear();
11449                    continue;
11450                }
11451                // Append the rest of the line and replace old reference with new one
11452                reindented_line.extend(chars);
11453                *line = Cow::Owned(reindented_line.clone());
11454                reindented_line.clear();
11455            }
11456        });
11457    }
11458
11459    pub fn convert_indentation_to_tabs(
11460        &mut self,
11461        _: &ConvertIndentationToTabs,
11462        window: &mut Window,
11463        cx: &mut Context<Self>,
11464    ) {
11465        let settings = self.buffer.read(cx).language_settings(cx);
11466        let tab_size = settings.tab_size.get() as usize;
11467
11468        self.manipulate_mutable_lines(window, cx, |lines| {
11469            // Allocates a reasonably sized buffer once for the whole loop
11470            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11471            // Avoids recomputing spaces that could be inserted many times
11472            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11473                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11474                .collect();
11475
11476            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11477                let mut chars = line.chars();
11478                let mut spaces_count = 0;
11479                let mut first_non_indent_char = None;
11480                let mut changed = false;
11481
11482                for ch in chars.by_ref() {
11483                    match ch {
11484                        ' ' => {
11485                            // Keep track of spaces. Append \t when we reach tab_size
11486                            spaces_count += 1;
11487                            changed = true;
11488                            if spaces_count == tab_size {
11489                                reindented_line.push('\t');
11490                                spaces_count = 0;
11491                            }
11492                        }
11493                        '\t' => {
11494                            reindented_line.push('\t');
11495                            spaces_count = 0;
11496                        }
11497                        _ => {
11498                            // Dont append it yet, we might have remaining spaces
11499                            first_non_indent_char = Some(ch);
11500                            break;
11501                        }
11502                    }
11503                }
11504
11505                if !changed {
11506                    reindented_line.clear();
11507                    continue;
11508                }
11509                // Remaining spaces that didn't make a full tab stop
11510                if spaces_count > 0 {
11511                    reindented_line.extend(&space_cache[spaces_count - 1]);
11512                }
11513                // If we consume an extra character that was not indentation, add it back
11514                if let Some(extra_char) = first_non_indent_char {
11515                    reindented_line.push(extra_char);
11516                }
11517                // Append the rest of the line and replace old reference with new one
11518                reindented_line.extend(chars);
11519                *line = Cow::Owned(reindented_line.clone());
11520                reindented_line.clear();
11521            }
11522        });
11523    }
11524
11525    pub fn convert_to_upper_case(
11526        &mut self,
11527        _: &ConvertToUpperCase,
11528        window: &mut Window,
11529        cx: &mut Context<Self>,
11530    ) {
11531        self.manipulate_text(window, cx, |text| text.to_uppercase())
11532    }
11533
11534    pub fn convert_to_lower_case(
11535        &mut self,
11536        _: &ConvertToLowerCase,
11537        window: &mut Window,
11538        cx: &mut Context<Self>,
11539    ) {
11540        self.manipulate_text(window, cx, |text| text.to_lowercase())
11541    }
11542
11543    pub fn convert_to_title_case(
11544        &mut self,
11545        _: &ConvertToTitleCase,
11546        window: &mut Window,
11547        cx: &mut Context<Self>,
11548    ) {
11549        self.manipulate_text(window, cx, |text| {
11550            text.split('\n')
11551                .map(|line| line.to_case(Case::Title))
11552                .join("\n")
11553        })
11554    }
11555
11556    pub fn convert_to_snake_case(
11557        &mut self,
11558        _: &ConvertToSnakeCase,
11559        window: &mut Window,
11560        cx: &mut Context<Self>,
11561    ) {
11562        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
11563    }
11564
11565    pub fn convert_to_kebab_case(
11566        &mut self,
11567        _: &ConvertToKebabCase,
11568        window: &mut Window,
11569        cx: &mut Context<Self>,
11570    ) {
11571        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
11572    }
11573
11574    pub fn convert_to_upper_camel_case(
11575        &mut self,
11576        _: &ConvertToUpperCamelCase,
11577        window: &mut Window,
11578        cx: &mut Context<Self>,
11579    ) {
11580        self.manipulate_text(window, cx, |text| {
11581            text.split('\n')
11582                .map(|line| line.to_case(Case::UpperCamel))
11583                .join("\n")
11584        })
11585    }
11586
11587    pub fn convert_to_lower_camel_case(
11588        &mut self,
11589        _: &ConvertToLowerCamelCase,
11590        window: &mut Window,
11591        cx: &mut Context<Self>,
11592    ) {
11593        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
11594    }
11595
11596    pub fn convert_to_opposite_case(
11597        &mut self,
11598        _: &ConvertToOppositeCase,
11599        window: &mut Window,
11600        cx: &mut Context<Self>,
11601    ) {
11602        self.manipulate_text(window, cx, |text| {
11603            text.chars()
11604                .fold(String::with_capacity(text.len()), |mut t, c| {
11605                    if c.is_uppercase() {
11606                        t.extend(c.to_lowercase());
11607                    } else {
11608                        t.extend(c.to_uppercase());
11609                    }
11610                    t
11611                })
11612        })
11613    }
11614
11615    pub fn convert_to_sentence_case(
11616        &mut self,
11617        _: &ConvertToSentenceCase,
11618        window: &mut Window,
11619        cx: &mut Context<Self>,
11620    ) {
11621        self.manipulate_text(window, cx, |text| text.to_case(Case::Sentence))
11622    }
11623
11624    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
11625        self.manipulate_text(window, cx, |text| {
11626            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
11627            if has_upper_case_characters {
11628                text.to_lowercase()
11629            } else {
11630                text.to_uppercase()
11631            }
11632        })
11633    }
11634
11635    pub fn convert_to_rot13(
11636        &mut self,
11637        _: &ConvertToRot13,
11638        window: &mut Window,
11639        cx: &mut Context<Self>,
11640    ) {
11641        self.manipulate_text(window, cx, |text| {
11642            text.chars()
11643                .map(|c| match c {
11644                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
11645                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
11646                    _ => c,
11647                })
11648                .collect()
11649        })
11650    }
11651
11652    pub fn convert_to_rot47(
11653        &mut self,
11654        _: &ConvertToRot47,
11655        window: &mut Window,
11656        cx: &mut Context<Self>,
11657    ) {
11658        self.manipulate_text(window, cx, |text| {
11659            text.chars()
11660                .map(|c| {
11661                    let code_point = c as u32;
11662                    if code_point >= 33 && code_point <= 126 {
11663                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
11664                    }
11665                    c
11666                })
11667                .collect()
11668        })
11669    }
11670
11671    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
11672    where
11673        Fn: FnMut(&str) -> String,
11674    {
11675        let buffer = self.buffer.read(cx).snapshot(cx);
11676
11677        let mut new_selections = Vec::new();
11678        let mut edits = Vec::new();
11679        let mut selection_adjustment = 0i32;
11680
11681        for selection in self.selections.all_adjusted(&self.display_snapshot(cx)) {
11682            let selection_is_empty = selection.is_empty();
11683
11684            let (start, end) = if selection_is_empty {
11685                let (word_range, _) = buffer.surrounding_word(selection.start, None);
11686                (word_range.start, word_range.end)
11687            } else {
11688                (
11689                    buffer.point_to_offset(selection.start),
11690                    buffer.point_to_offset(selection.end),
11691                )
11692            };
11693
11694            let text = buffer.text_for_range(start..end).collect::<String>();
11695            let old_length = text.len() as i32;
11696            let text = callback(&text);
11697
11698            new_selections.push(Selection {
11699                start: (start as i32 - selection_adjustment) as usize,
11700                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
11701                goal: SelectionGoal::None,
11702                id: selection.id,
11703                reversed: selection.reversed,
11704            });
11705
11706            selection_adjustment += old_length - text.len() as i32;
11707
11708            edits.push((start..end, text));
11709        }
11710
11711        self.transact(window, cx, |this, window, cx| {
11712            this.buffer.update(cx, |buffer, cx| {
11713                buffer.edit(edits, None, cx);
11714            });
11715
11716            this.change_selections(Default::default(), window, cx, |s| {
11717                s.select(new_selections);
11718            });
11719
11720            this.request_autoscroll(Autoscroll::fit(), cx);
11721        });
11722    }
11723
11724    pub fn move_selection_on_drop(
11725        &mut self,
11726        selection: &Selection<Anchor>,
11727        target: DisplayPoint,
11728        is_cut: bool,
11729        window: &mut Window,
11730        cx: &mut Context<Self>,
11731    ) {
11732        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11733        let buffer = display_map.buffer_snapshot();
11734        let mut edits = Vec::new();
11735        let insert_point = display_map
11736            .clip_point(target, Bias::Left)
11737            .to_point(&display_map);
11738        let text = buffer
11739            .text_for_range(selection.start..selection.end)
11740            .collect::<String>();
11741        if is_cut {
11742            edits.push(((selection.start..selection.end), String::new()));
11743        }
11744        let insert_anchor = buffer.anchor_before(insert_point);
11745        edits.push(((insert_anchor..insert_anchor), text));
11746        let last_edit_start = insert_anchor.bias_left(buffer);
11747        let last_edit_end = insert_anchor.bias_right(buffer);
11748        self.transact(window, cx, |this, window, cx| {
11749            this.buffer.update(cx, |buffer, cx| {
11750                buffer.edit(edits, None, cx);
11751            });
11752            this.change_selections(Default::default(), window, cx, |s| {
11753                s.select_anchor_ranges([last_edit_start..last_edit_end]);
11754            });
11755        });
11756    }
11757
11758    pub fn clear_selection_drag_state(&mut self) {
11759        self.selection_drag_state = SelectionDragState::None;
11760    }
11761
11762    pub fn duplicate(
11763        &mut self,
11764        upwards: bool,
11765        whole_lines: bool,
11766        window: &mut Window,
11767        cx: &mut Context<Self>,
11768    ) {
11769        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11770
11771        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11772        let buffer = display_map.buffer_snapshot();
11773        let selections = self.selections.all::<Point>(&display_map);
11774
11775        let mut edits = Vec::new();
11776        let mut selections_iter = selections.iter().peekable();
11777        while let Some(selection) = selections_iter.next() {
11778            let mut rows = selection.spanned_rows(false, &display_map);
11779            // duplicate line-wise
11780            if whole_lines || selection.start == selection.end {
11781                // Avoid duplicating the same lines twice.
11782                while let Some(next_selection) = selections_iter.peek() {
11783                    let next_rows = next_selection.spanned_rows(false, &display_map);
11784                    if next_rows.start < rows.end {
11785                        rows.end = next_rows.end;
11786                        selections_iter.next().unwrap();
11787                    } else {
11788                        break;
11789                    }
11790                }
11791
11792                // Copy the text from the selected row region and splice it either at the start
11793                // or end of the region.
11794                let start = Point::new(rows.start.0, 0);
11795                let end = Point::new(
11796                    rows.end.previous_row().0,
11797                    buffer.line_len(rows.end.previous_row()),
11798                );
11799
11800                let mut text = buffer.text_for_range(start..end).collect::<String>();
11801
11802                let insert_location = if upwards {
11803                    // When duplicating upward, we need to insert before the current line.
11804                    // If we're on the last line and it doesn't end with a newline,
11805                    // we need to add a newline before the duplicated content.
11806                    let needs_leading_newline = rows.end.0 >= buffer.max_point().row
11807                        && buffer.max_point().column > 0
11808                        && !text.ends_with('\n');
11809
11810                    if needs_leading_newline {
11811                        text.insert(0, '\n');
11812                        end
11813                    } else {
11814                        text.push('\n');
11815                        Point::new(rows.start.0, 0)
11816                    }
11817                } else {
11818                    text.push('\n');
11819                    start
11820                };
11821                edits.push((insert_location..insert_location, text));
11822            } else {
11823                // duplicate character-wise
11824                let start = selection.start;
11825                let end = selection.end;
11826                let text = buffer.text_for_range(start..end).collect::<String>();
11827                edits.push((selection.end..selection.end, text));
11828            }
11829        }
11830
11831        self.transact(window, cx, |this, window, cx| {
11832            this.buffer.update(cx, |buffer, cx| {
11833                buffer.edit(edits, None, cx);
11834            });
11835
11836            // When duplicating upward with whole lines, move the cursor to the duplicated line
11837            if upwards && whole_lines {
11838                let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
11839
11840                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
11841                    let mut new_ranges = Vec::new();
11842                    let selections = s.all::<Point>(&display_map);
11843                    let mut selections_iter = selections.iter().peekable();
11844
11845                    while let Some(first_selection) = selections_iter.next() {
11846                        // Group contiguous selections together to find the total row span
11847                        let mut group_selections = vec![first_selection];
11848                        let mut rows = first_selection.spanned_rows(false, &display_map);
11849
11850                        while let Some(next_selection) = selections_iter.peek() {
11851                            let next_rows = next_selection.spanned_rows(false, &display_map);
11852                            if next_rows.start < rows.end {
11853                                rows.end = next_rows.end;
11854                                group_selections.push(selections_iter.next().unwrap());
11855                            } else {
11856                                break;
11857                            }
11858                        }
11859
11860                        let row_count = rows.end.0 - rows.start.0;
11861
11862                        // Move all selections in this group up by the total number of duplicated rows
11863                        for selection in group_selections {
11864                            let new_start = Point::new(
11865                                selection.start.row.saturating_sub(row_count),
11866                                selection.start.column,
11867                            );
11868
11869                            let new_end = Point::new(
11870                                selection.end.row.saturating_sub(row_count),
11871                                selection.end.column,
11872                            );
11873
11874                            new_ranges.push(new_start..new_end);
11875                        }
11876                    }
11877
11878                    s.select_ranges(new_ranges);
11879                });
11880            }
11881
11882            this.request_autoscroll(Autoscroll::fit(), cx);
11883        });
11884    }
11885
11886    pub fn duplicate_line_up(
11887        &mut self,
11888        _: &DuplicateLineUp,
11889        window: &mut Window,
11890        cx: &mut Context<Self>,
11891    ) {
11892        self.duplicate(true, true, window, cx);
11893    }
11894
11895    pub fn duplicate_line_down(
11896        &mut self,
11897        _: &DuplicateLineDown,
11898        window: &mut Window,
11899        cx: &mut Context<Self>,
11900    ) {
11901        self.duplicate(false, true, window, cx);
11902    }
11903
11904    pub fn duplicate_selection(
11905        &mut self,
11906        _: &DuplicateSelection,
11907        window: &mut Window,
11908        cx: &mut Context<Self>,
11909    ) {
11910        self.duplicate(false, false, window, cx);
11911    }
11912
11913    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
11914        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11915        if self.mode.is_single_line() {
11916            cx.propagate();
11917            return;
11918        }
11919
11920        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11921        let buffer = self.buffer.read(cx).snapshot(cx);
11922
11923        let mut edits = Vec::new();
11924        let mut unfold_ranges = Vec::new();
11925        let mut refold_creases = Vec::new();
11926
11927        let selections = self.selections.all::<Point>(&display_map);
11928        let mut selections = selections.iter().peekable();
11929        let mut contiguous_row_selections = Vec::new();
11930        let mut new_selections = Vec::new();
11931
11932        while let Some(selection) = selections.next() {
11933            // Find all the selections that span a contiguous row range
11934            let (start_row, end_row) = consume_contiguous_rows(
11935                &mut contiguous_row_selections,
11936                selection,
11937                &display_map,
11938                &mut selections,
11939            );
11940
11941            // Move the text spanned by the row range to be before the line preceding the row range
11942            if start_row.0 > 0 {
11943                let range_to_move = Point::new(
11944                    start_row.previous_row().0,
11945                    buffer.line_len(start_row.previous_row()),
11946                )
11947                    ..Point::new(
11948                        end_row.previous_row().0,
11949                        buffer.line_len(end_row.previous_row()),
11950                    );
11951                let insertion_point = display_map
11952                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
11953                    .0;
11954
11955                // Don't move lines across excerpts
11956                if buffer
11957                    .excerpt_containing(insertion_point..range_to_move.end)
11958                    .is_some()
11959                {
11960                    let text = buffer
11961                        .text_for_range(range_to_move.clone())
11962                        .flat_map(|s| s.chars())
11963                        .skip(1)
11964                        .chain(['\n'])
11965                        .collect::<String>();
11966
11967                    edits.push((
11968                        buffer.anchor_after(range_to_move.start)
11969                            ..buffer.anchor_before(range_to_move.end),
11970                        String::new(),
11971                    ));
11972                    let insertion_anchor = buffer.anchor_after(insertion_point);
11973                    edits.push((insertion_anchor..insertion_anchor, text));
11974
11975                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
11976
11977                    // Move selections up
11978                    new_selections.extend(contiguous_row_selections.drain(..).map(
11979                        |mut selection| {
11980                            selection.start.row -= row_delta;
11981                            selection.end.row -= row_delta;
11982                            selection
11983                        },
11984                    ));
11985
11986                    // Move folds up
11987                    unfold_ranges.push(range_to_move.clone());
11988                    for fold in display_map.folds_in_range(
11989                        buffer.anchor_before(range_to_move.start)
11990                            ..buffer.anchor_after(range_to_move.end),
11991                    ) {
11992                        let mut start = fold.range.start.to_point(&buffer);
11993                        let mut end = fold.range.end.to_point(&buffer);
11994                        start.row -= row_delta;
11995                        end.row -= row_delta;
11996                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11997                    }
11998                }
11999            }
12000
12001            // If we didn't move line(s), preserve the existing selections
12002            new_selections.append(&mut contiguous_row_selections);
12003        }
12004
12005        self.transact(window, cx, |this, window, cx| {
12006            this.unfold_ranges(&unfold_ranges, true, true, cx);
12007            this.buffer.update(cx, |buffer, cx| {
12008                for (range, text) in edits {
12009                    buffer.edit([(range, text)], None, cx);
12010                }
12011            });
12012            this.fold_creases(refold_creases, true, window, cx);
12013            this.change_selections(Default::default(), window, cx, |s| {
12014                s.select(new_selections);
12015            })
12016        });
12017    }
12018
12019    pub fn move_line_down(
12020        &mut self,
12021        _: &MoveLineDown,
12022        window: &mut Window,
12023        cx: &mut Context<Self>,
12024    ) {
12025        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12026        if self.mode.is_single_line() {
12027            cx.propagate();
12028            return;
12029        }
12030
12031        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12032        let buffer = self.buffer.read(cx).snapshot(cx);
12033
12034        let mut edits = Vec::new();
12035        let mut unfold_ranges = Vec::new();
12036        let mut refold_creases = Vec::new();
12037
12038        let selections = self.selections.all::<Point>(&display_map);
12039        let mut selections = selections.iter().peekable();
12040        let mut contiguous_row_selections = Vec::new();
12041        let mut new_selections = Vec::new();
12042
12043        while let Some(selection) = selections.next() {
12044            // Find all the selections that span a contiguous row range
12045            let (start_row, end_row) = consume_contiguous_rows(
12046                &mut contiguous_row_selections,
12047                selection,
12048                &display_map,
12049                &mut selections,
12050            );
12051
12052            // Move the text spanned by the row range to be after the last line of the row range
12053            if end_row.0 <= buffer.max_point().row {
12054                let range_to_move =
12055                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
12056                let insertion_point = display_map
12057                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
12058                    .0;
12059
12060                // Don't move lines across excerpt boundaries
12061                if buffer
12062                    .excerpt_containing(range_to_move.start..insertion_point)
12063                    .is_some()
12064                {
12065                    let mut text = String::from("\n");
12066                    text.extend(buffer.text_for_range(range_to_move.clone()));
12067                    text.pop(); // Drop trailing newline
12068                    edits.push((
12069                        buffer.anchor_after(range_to_move.start)
12070                            ..buffer.anchor_before(range_to_move.end),
12071                        String::new(),
12072                    ));
12073                    let insertion_anchor = buffer.anchor_after(insertion_point);
12074                    edits.push((insertion_anchor..insertion_anchor, text));
12075
12076                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
12077
12078                    // Move selections down
12079                    new_selections.extend(contiguous_row_selections.drain(..).map(
12080                        |mut selection| {
12081                            selection.start.row += row_delta;
12082                            selection.end.row += row_delta;
12083                            selection
12084                        },
12085                    ));
12086
12087                    // Move folds down
12088                    unfold_ranges.push(range_to_move.clone());
12089                    for fold in display_map.folds_in_range(
12090                        buffer.anchor_before(range_to_move.start)
12091                            ..buffer.anchor_after(range_to_move.end),
12092                    ) {
12093                        let mut start = fold.range.start.to_point(&buffer);
12094                        let mut end = fold.range.end.to_point(&buffer);
12095                        start.row += row_delta;
12096                        end.row += row_delta;
12097                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
12098                    }
12099                }
12100            }
12101
12102            // If we didn't move line(s), preserve the existing selections
12103            new_selections.append(&mut contiguous_row_selections);
12104        }
12105
12106        self.transact(window, cx, |this, window, cx| {
12107            this.unfold_ranges(&unfold_ranges, true, true, cx);
12108            this.buffer.update(cx, |buffer, cx| {
12109                for (range, text) in edits {
12110                    buffer.edit([(range, text)], None, cx);
12111                }
12112            });
12113            this.fold_creases(refold_creases, true, window, cx);
12114            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
12115        });
12116    }
12117
12118    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
12119        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12120        let text_layout_details = &self.text_layout_details(window);
12121        self.transact(window, cx, |this, window, cx| {
12122            let edits = this.change_selections(Default::default(), window, cx, |s| {
12123                let mut edits: Vec<(Range<usize>, String)> = Default::default();
12124                s.move_with(|display_map, selection| {
12125                    if !selection.is_empty() {
12126                        return;
12127                    }
12128
12129                    let mut head = selection.head();
12130                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
12131                    if head.column() == display_map.line_len(head.row()) {
12132                        transpose_offset = display_map
12133                            .buffer_snapshot()
12134                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
12135                    }
12136
12137                    if transpose_offset == 0 {
12138                        return;
12139                    }
12140
12141                    *head.column_mut() += 1;
12142                    head = display_map.clip_point(head, Bias::Right);
12143                    let goal = SelectionGoal::HorizontalPosition(
12144                        display_map
12145                            .x_for_display_point(head, text_layout_details)
12146                            .into(),
12147                    );
12148                    selection.collapse_to(head, goal);
12149
12150                    let transpose_start = display_map
12151                        .buffer_snapshot()
12152                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
12153                    if edits.last().is_none_or(|e| e.0.end <= transpose_start) {
12154                        let transpose_end = display_map
12155                            .buffer_snapshot()
12156                            .clip_offset(transpose_offset + 1, Bias::Right);
12157                        if let Some(ch) = display_map
12158                            .buffer_snapshot()
12159                            .chars_at(transpose_start)
12160                            .next()
12161                        {
12162                            edits.push((transpose_start..transpose_offset, String::new()));
12163                            edits.push((transpose_end..transpose_end, ch.to_string()));
12164                        }
12165                    }
12166                });
12167                edits
12168            });
12169            this.buffer
12170                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12171            let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
12172            this.change_selections(Default::default(), window, cx, |s| {
12173                s.select(selections);
12174            });
12175        });
12176    }
12177
12178    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
12179        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12180        if self.mode.is_single_line() {
12181            cx.propagate();
12182            return;
12183        }
12184
12185        self.rewrap_impl(RewrapOptions::default(), cx)
12186    }
12187
12188    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
12189        let buffer = self.buffer.read(cx).snapshot(cx);
12190        let selections = self.selections.all::<Point>(&self.display_snapshot(cx));
12191
12192        #[derive(Clone, Debug, PartialEq)]
12193        enum CommentFormat {
12194            /// single line comment, with prefix for line
12195            Line(String),
12196            /// single line within a block comment, with prefix for line
12197            BlockLine(String),
12198            /// a single line of a block comment that includes the initial delimiter
12199            BlockCommentWithStart(BlockCommentConfig),
12200            /// a single line of a block comment that includes the ending delimiter
12201            BlockCommentWithEnd(BlockCommentConfig),
12202        }
12203
12204        // Split selections to respect paragraph, indent, and comment prefix boundaries.
12205        let wrap_ranges = selections.into_iter().flat_map(|selection| {
12206            let mut non_blank_rows_iter = (selection.start.row..=selection.end.row)
12207                .filter(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
12208                .peekable();
12209
12210            let first_row = if let Some(&row) = non_blank_rows_iter.peek() {
12211                row
12212            } else {
12213                return Vec::new();
12214            };
12215
12216            let language_settings = buffer.language_settings_at(selection.head(), cx);
12217            let language_scope = buffer.language_scope_at(selection.head());
12218
12219            let indent_and_prefix_for_row =
12220                |row: u32| -> (IndentSize, Option<CommentFormat>, Option<String>) {
12221                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
12222                    let (comment_prefix, rewrap_prefix) = if let Some(language_scope) =
12223                        &language_scope
12224                    {
12225                        let indent_end = Point::new(row, indent.len);
12226                        let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
12227                        let line_text_after_indent = buffer
12228                            .text_for_range(indent_end..line_end)
12229                            .collect::<String>();
12230
12231                        let is_within_comment_override = buffer
12232                            .language_scope_at(indent_end)
12233                            .is_some_and(|scope| scope.override_name() == Some("comment"));
12234                        let comment_delimiters = if is_within_comment_override {
12235                            // we are within a comment syntax node, but we don't
12236                            // yet know what kind of comment: block, doc or line
12237                            match (
12238                                language_scope.documentation_comment(),
12239                                language_scope.block_comment(),
12240                            ) {
12241                                (Some(config), _) | (_, Some(config))
12242                                    if buffer.contains_str_at(indent_end, &config.start) =>
12243                                {
12244                                    Some(CommentFormat::BlockCommentWithStart(config.clone()))
12245                                }
12246                                (Some(config), _) | (_, Some(config))
12247                                    if line_text_after_indent.ends_with(config.end.as_ref()) =>
12248                                {
12249                                    Some(CommentFormat::BlockCommentWithEnd(config.clone()))
12250                                }
12251                                (Some(config), _) | (_, Some(config))
12252                                    if buffer.contains_str_at(indent_end, &config.prefix) =>
12253                                {
12254                                    Some(CommentFormat::BlockLine(config.prefix.to_string()))
12255                                }
12256                                (_, _) => language_scope
12257                                    .line_comment_prefixes()
12258                                    .iter()
12259                                    .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12260                                    .map(|prefix| CommentFormat::Line(prefix.to_string())),
12261                            }
12262                        } else {
12263                            // we not in an overridden comment node, but we may
12264                            // be within a non-overridden line comment node
12265                            language_scope
12266                                .line_comment_prefixes()
12267                                .iter()
12268                                .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12269                                .map(|prefix| CommentFormat::Line(prefix.to_string()))
12270                        };
12271
12272                        let rewrap_prefix = language_scope
12273                            .rewrap_prefixes()
12274                            .iter()
12275                            .find_map(|prefix_regex| {
12276                                prefix_regex.find(&line_text_after_indent).map(|mat| {
12277                                    if mat.start() == 0 {
12278                                        Some(mat.as_str().to_string())
12279                                    } else {
12280                                        None
12281                                    }
12282                                })
12283                            })
12284                            .flatten();
12285                        (comment_delimiters, rewrap_prefix)
12286                    } else {
12287                        (None, None)
12288                    };
12289                    (indent, comment_prefix, rewrap_prefix)
12290                };
12291
12292            let mut ranges = Vec::new();
12293            let from_empty_selection = selection.is_empty();
12294
12295            let mut current_range_start = first_row;
12296            let mut prev_row = first_row;
12297            let (
12298                mut current_range_indent,
12299                mut current_range_comment_delimiters,
12300                mut current_range_rewrap_prefix,
12301            ) = indent_and_prefix_for_row(first_row);
12302
12303            for row in non_blank_rows_iter.skip(1) {
12304                let has_paragraph_break = row > prev_row + 1;
12305
12306                let (row_indent, row_comment_delimiters, row_rewrap_prefix) =
12307                    indent_and_prefix_for_row(row);
12308
12309                let has_indent_change = row_indent != current_range_indent;
12310                let has_comment_change = row_comment_delimiters != current_range_comment_delimiters;
12311
12312                let has_boundary_change = has_comment_change
12313                    || row_rewrap_prefix.is_some()
12314                    || (has_indent_change && current_range_comment_delimiters.is_some());
12315
12316                if has_paragraph_break || has_boundary_change {
12317                    ranges.push((
12318                        language_settings.clone(),
12319                        Point::new(current_range_start, 0)
12320                            ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12321                        current_range_indent,
12322                        current_range_comment_delimiters.clone(),
12323                        current_range_rewrap_prefix.clone(),
12324                        from_empty_selection,
12325                    ));
12326                    current_range_start = row;
12327                    current_range_indent = row_indent;
12328                    current_range_comment_delimiters = row_comment_delimiters;
12329                    current_range_rewrap_prefix = row_rewrap_prefix;
12330                }
12331                prev_row = row;
12332            }
12333
12334            ranges.push((
12335                language_settings.clone(),
12336                Point::new(current_range_start, 0)
12337                    ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12338                current_range_indent,
12339                current_range_comment_delimiters,
12340                current_range_rewrap_prefix,
12341                from_empty_selection,
12342            ));
12343
12344            ranges
12345        });
12346
12347        let mut edits = Vec::new();
12348        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
12349
12350        for (
12351            language_settings,
12352            wrap_range,
12353            mut indent_size,
12354            comment_prefix,
12355            rewrap_prefix,
12356            from_empty_selection,
12357        ) in wrap_ranges
12358        {
12359            let mut start_row = wrap_range.start.row;
12360            let mut end_row = wrap_range.end.row;
12361
12362            // Skip selections that overlap with a range that has already been rewrapped.
12363            let selection_range = start_row..end_row;
12364            if rewrapped_row_ranges
12365                .iter()
12366                .any(|range| range.overlaps(&selection_range))
12367            {
12368                continue;
12369            }
12370
12371            let tab_size = language_settings.tab_size;
12372
12373            let (line_prefix, inside_comment) = match &comment_prefix {
12374                Some(CommentFormat::Line(prefix) | CommentFormat::BlockLine(prefix)) => {
12375                    (Some(prefix.as_str()), true)
12376                }
12377                Some(CommentFormat::BlockCommentWithEnd(BlockCommentConfig { prefix, .. })) => {
12378                    (Some(prefix.as_ref()), true)
12379                }
12380                Some(CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12381                    start: _,
12382                    end: _,
12383                    prefix,
12384                    tab_size,
12385                })) => {
12386                    indent_size.len += tab_size;
12387                    (Some(prefix.as_ref()), true)
12388                }
12389                None => (None, false),
12390            };
12391            let indent_prefix = indent_size.chars().collect::<String>();
12392            let line_prefix = format!("{indent_prefix}{}", line_prefix.unwrap_or(""));
12393
12394            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
12395                RewrapBehavior::InComments => inside_comment,
12396                RewrapBehavior::InSelections => !wrap_range.is_empty(),
12397                RewrapBehavior::Anywhere => true,
12398            };
12399
12400            let should_rewrap = options.override_language_settings
12401                || allow_rewrap_based_on_language
12402                || self.hard_wrap.is_some();
12403            if !should_rewrap {
12404                continue;
12405            }
12406
12407            if from_empty_selection {
12408                'expand_upwards: while start_row > 0 {
12409                    let prev_row = start_row - 1;
12410                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
12411                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
12412                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
12413                    {
12414                        start_row = prev_row;
12415                    } else {
12416                        break 'expand_upwards;
12417                    }
12418                }
12419
12420                'expand_downwards: while end_row < buffer.max_point().row {
12421                    let next_row = end_row + 1;
12422                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
12423                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
12424                        && !buffer.is_line_blank(MultiBufferRow(next_row))
12425                    {
12426                        end_row = next_row;
12427                    } else {
12428                        break 'expand_downwards;
12429                    }
12430                }
12431            }
12432
12433            let start = Point::new(start_row, 0);
12434            let start_offset = ToOffset::to_offset(&start, &buffer);
12435            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
12436            let selection_text = buffer.text_for_range(start..end).collect::<String>();
12437            let mut first_line_delimiter = None;
12438            let mut last_line_delimiter = None;
12439            let Some(lines_without_prefixes) = selection_text
12440                .lines()
12441                .enumerate()
12442                .map(|(ix, line)| {
12443                    let line_trimmed = line.trim_start();
12444                    if rewrap_prefix.is_some() && ix > 0 {
12445                        Ok(line_trimmed)
12446                    } else if let Some(
12447                        CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12448                            start,
12449                            prefix,
12450                            end,
12451                            tab_size,
12452                        })
12453                        | CommentFormat::BlockCommentWithEnd(BlockCommentConfig {
12454                            start,
12455                            prefix,
12456                            end,
12457                            tab_size,
12458                        }),
12459                    ) = &comment_prefix
12460                    {
12461                        let line_trimmed = line_trimmed
12462                            .strip_prefix(start.as_ref())
12463                            .map(|s| {
12464                                let mut indent_size = indent_size;
12465                                indent_size.len -= tab_size;
12466                                let indent_prefix: String = indent_size.chars().collect();
12467                                first_line_delimiter = Some((indent_prefix, start));
12468                                s.trim_start()
12469                            })
12470                            .unwrap_or(line_trimmed);
12471                        let line_trimmed = line_trimmed
12472                            .strip_suffix(end.as_ref())
12473                            .map(|s| {
12474                                last_line_delimiter = Some(end);
12475                                s.trim_end()
12476                            })
12477                            .unwrap_or(line_trimmed);
12478                        let line_trimmed = line_trimmed
12479                            .strip_prefix(prefix.as_ref())
12480                            .unwrap_or(line_trimmed);
12481                        Ok(line_trimmed)
12482                    } else if let Some(CommentFormat::BlockLine(prefix)) = &comment_prefix {
12483                        line_trimmed.strip_prefix(prefix).with_context(|| {
12484                            format!("line did not start with prefix {prefix:?}: {line:?}")
12485                        })
12486                    } else {
12487                        line_trimmed
12488                            .strip_prefix(&line_prefix.trim_start())
12489                            .with_context(|| {
12490                                format!("line did not start with prefix {line_prefix:?}: {line:?}")
12491                            })
12492                    }
12493                })
12494                .collect::<Result<Vec<_>, _>>()
12495                .log_err()
12496            else {
12497                continue;
12498            };
12499
12500            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
12501                buffer
12502                    .language_settings_at(Point::new(start_row, 0), cx)
12503                    .preferred_line_length as usize
12504            });
12505
12506            let subsequent_lines_prefix = if let Some(rewrap_prefix_str) = &rewrap_prefix {
12507                format!("{}{}", indent_prefix, " ".repeat(rewrap_prefix_str.len()))
12508            } else {
12509                line_prefix.clone()
12510            };
12511
12512            let wrapped_text = {
12513                let mut wrapped_text = wrap_with_prefix(
12514                    line_prefix,
12515                    subsequent_lines_prefix,
12516                    lines_without_prefixes.join("\n"),
12517                    wrap_column,
12518                    tab_size,
12519                    options.preserve_existing_whitespace,
12520                );
12521
12522                if let Some((indent, delimiter)) = first_line_delimiter {
12523                    wrapped_text = format!("{indent}{delimiter}\n{wrapped_text}");
12524                }
12525                if let Some(last_line) = last_line_delimiter {
12526                    wrapped_text = format!("{wrapped_text}\n{indent_prefix}{last_line}");
12527                }
12528
12529                wrapped_text
12530            };
12531
12532            // TODO: should always use char-based diff while still supporting cursor behavior that
12533            // matches vim.
12534            let mut diff_options = DiffOptions::default();
12535            if options.override_language_settings {
12536                diff_options.max_word_diff_len = 0;
12537                diff_options.max_word_diff_line_count = 0;
12538            } else {
12539                diff_options.max_word_diff_len = usize::MAX;
12540                diff_options.max_word_diff_line_count = usize::MAX;
12541            }
12542
12543            for (old_range, new_text) in
12544                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
12545            {
12546                let edit_start = buffer.anchor_after(start_offset + old_range.start);
12547                let edit_end = buffer.anchor_after(start_offset + old_range.end);
12548                edits.push((edit_start..edit_end, new_text));
12549            }
12550
12551            rewrapped_row_ranges.push(start_row..=end_row);
12552        }
12553
12554        self.buffer
12555            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12556    }
12557
12558    pub fn cut_common(
12559        &mut self,
12560        cut_no_selection_line: bool,
12561        window: &mut Window,
12562        cx: &mut Context<Self>,
12563    ) -> ClipboardItem {
12564        let mut text = String::new();
12565        let buffer = self.buffer.read(cx).snapshot(cx);
12566        let mut selections = self.selections.all::<Point>(&self.display_snapshot(cx));
12567        let mut clipboard_selections = Vec::with_capacity(selections.len());
12568        {
12569            let max_point = buffer.max_point();
12570            let mut is_first = true;
12571            for selection in &mut selections {
12572                let is_entire_line =
12573                    (selection.is_empty() && cut_no_selection_line) || self.selections.line_mode();
12574                if is_entire_line {
12575                    selection.start = Point::new(selection.start.row, 0);
12576                    if !selection.is_empty() && selection.end.column == 0 {
12577                        selection.end = cmp::min(max_point, selection.end);
12578                    } else {
12579                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
12580                    }
12581                    selection.goal = SelectionGoal::None;
12582                }
12583                if is_first {
12584                    is_first = false;
12585                } else {
12586                    text += "\n";
12587                }
12588                let mut len = 0;
12589                for chunk in buffer.text_for_range(selection.start..selection.end) {
12590                    text.push_str(chunk);
12591                    len += chunk.len();
12592                }
12593                clipboard_selections.push(ClipboardSelection {
12594                    len,
12595                    is_entire_line,
12596                    first_line_indent: buffer
12597                        .indent_size_for_line(MultiBufferRow(selection.start.row))
12598                        .len,
12599                });
12600            }
12601        }
12602
12603        self.transact(window, cx, |this, window, cx| {
12604            this.change_selections(Default::default(), window, cx, |s| {
12605                s.select(selections);
12606            });
12607            this.insert("", window, cx);
12608        });
12609        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
12610    }
12611
12612    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
12613        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12614        let item = self.cut_common(true, window, cx);
12615        cx.write_to_clipboard(item);
12616    }
12617
12618    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
12619        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12620        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12621            s.move_with(|snapshot, sel| {
12622                if sel.is_empty() {
12623                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()));
12624                }
12625                if sel.is_empty() {
12626                    sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
12627                }
12628            });
12629        });
12630        let item = self.cut_common(false, window, cx);
12631        cx.set_global(KillRing(item))
12632    }
12633
12634    pub fn kill_ring_yank(
12635        &mut self,
12636        _: &KillRingYank,
12637        window: &mut Window,
12638        cx: &mut Context<Self>,
12639    ) {
12640        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12641        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
12642            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
12643                (kill_ring.text().to_string(), kill_ring.metadata_json())
12644            } else {
12645                return;
12646            }
12647        } else {
12648            return;
12649        };
12650        self.do_paste(&text, metadata, false, window, cx);
12651    }
12652
12653    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
12654        self.do_copy(true, cx);
12655    }
12656
12657    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
12658        self.do_copy(false, cx);
12659    }
12660
12661    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
12662        let selections = self.selections.all::<Point>(&self.display_snapshot(cx));
12663        let buffer = self.buffer.read(cx).read(cx);
12664        let mut text = String::new();
12665
12666        let mut clipboard_selections = Vec::with_capacity(selections.len());
12667        {
12668            let max_point = buffer.max_point();
12669            let mut is_first = true;
12670            for selection in &selections {
12671                let mut start = selection.start;
12672                let mut end = selection.end;
12673                let is_entire_line = selection.is_empty() || self.selections.line_mode();
12674                let mut add_trailing_newline = false;
12675                if is_entire_line {
12676                    start = Point::new(start.row, 0);
12677                    let next_line_start = Point::new(end.row + 1, 0);
12678                    if next_line_start <= max_point {
12679                        end = next_line_start;
12680                    } else {
12681                        // We're on the last line without a trailing newline.
12682                        // Copy to the end of the line and add a newline afterwards.
12683                        end = Point::new(end.row, buffer.line_len(MultiBufferRow(end.row)));
12684                        add_trailing_newline = true;
12685                    }
12686                }
12687
12688                let mut trimmed_selections = Vec::new();
12689                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
12690                    let row = MultiBufferRow(start.row);
12691                    let first_indent = buffer.indent_size_for_line(row);
12692                    if first_indent.len == 0 || start.column > first_indent.len {
12693                        trimmed_selections.push(start..end);
12694                    } else {
12695                        trimmed_selections.push(
12696                            Point::new(row.0, first_indent.len)
12697                                ..Point::new(row.0, buffer.line_len(row)),
12698                        );
12699                        for row in start.row + 1..=end.row {
12700                            let mut line_len = buffer.line_len(MultiBufferRow(row));
12701                            if row == end.row {
12702                                line_len = end.column;
12703                            }
12704                            if line_len == 0 {
12705                                trimmed_selections
12706                                    .push(Point::new(row, 0)..Point::new(row, line_len));
12707                                continue;
12708                            }
12709                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
12710                            if row_indent_size.len >= first_indent.len {
12711                                trimmed_selections.push(
12712                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
12713                                );
12714                            } else {
12715                                trimmed_selections.clear();
12716                                trimmed_selections.push(start..end);
12717                                break;
12718                            }
12719                        }
12720                    }
12721                } else {
12722                    trimmed_selections.push(start..end);
12723                }
12724
12725                for trimmed_range in trimmed_selections {
12726                    if is_first {
12727                        is_first = false;
12728                    } else {
12729                        text += "\n";
12730                    }
12731                    let mut len = 0;
12732                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
12733                        text.push_str(chunk);
12734                        len += chunk.len();
12735                    }
12736                    if add_trailing_newline {
12737                        text.push('\n');
12738                        len += 1;
12739                    }
12740                    clipboard_selections.push(ClipboardSelection {
12741                        len,
12742                        is_entire_line,
12743                        first_line_indent: buffer
12744                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
12745                            .len,
12746                    });
12747                }
12748            }
12749        }
12750
12751        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
12752            text,
12753            clipboard_selections,
12754        ));
12755    }
12756
12757    pub fn do_paste(
12758        &mut self,
12759        text: &String,
12760        clipboard_selections: Option<Vec<ClipboardSelection>>,
12761        handle_entire_lines: bool,
12762        window: &mut Window,
12763        cx: &mut Context<Self>,
12764    ) {
12765        if self.read_only(cx) {
12766            return;
12767        }
12768
12769        let clipboard_text = Cow::Borrowed(text.as_str());
12770
12771        self.transact(window, cx, |this, window, cx| {
12772            let had_active_edit_prediction = this.has_active_edit_prediction();
12773            let display_map = this.display_snapshot(cx);
12774            let old_selections = this.selections.all::<usize>(&display_map);
12775            let cursor_offset = this.selections.last::<usize>(&display_map).head();
12776
12777            if let Some(mut clipboard_selections) = clipboard_selections {
12778                let all_selections_were_entire_line =
12779                    clipboard_selections.iter().all(|s| s.is_entire_line);
12780                let first_selection_indent_column =
12781                    clipboard_selections.first().map(|s| s.first_line_indent);
12782                if clipboard_selections.len() != old_selections.len() {
12783                    clipboard_selections.drain(..);
12784                }
12785                let mut auto_indent_on_paste = true;
12786
12787                this.buffer.update(cx, |buffer, cx| {
12788                    let snapshot = buffer.read(cx);
12789                    auto_indent_on_paste = snapshot
12790                        .language_settings_at(cursor_offset, cx)
12791                        .auto_indent_on_paste;
12792
12793                    let mut start_offset = 0;
12794                    let mut edits = Vec::new();
12795                    let mut original_indent_columns = Vec::new();
12796                    for (ix, selection) in old_selections.iter().enumerate() {
12797                        let to_insert;
12798                        let entire_line;
12799                        let original_indent_column;
12800                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
12801                            let end_offset = start_offset + clipboard_selection.len;
12802                            to_insert = &clipboard_text[start_offset..end_offset];
12803                            entire_line = clipboard_selection.is_entire_line;
12804                            start_offset = end_offset + 1;
12805                            original_indent_column = Some(clipboard_selection.first_line_indent);
12806                        } else {
12807                            to_insert = &*clipboard_text;
12808                            entire_line = all_selections_were_entire_line;
12809                            original_indent_column = first_selection_indent_column
12810                        }
12811
12812                        let (range, to_insert) =
12813                            if selection.is_empty() && handle_entire_lines && entire_line {
12814                                // If the corresponding selection was empty when this slice of the
12815                                // clipboard text was written, then the entire line containing the
12816                                // selection was copied. If this selection is also currently empty,
12817                                // then paste the line before the current line of the buffer.
12818                                let column = selection.start.to_point(&snapshot).column as usize;
12819                                let line_start = selection.start - column;
12820                                (line_start..line_start, Cow::Borrowed(to_insert))
12821                            } else {
12822                                let language = snapshot.language_at(selection.head());
12823                                let range = selection.range();
12824                                if let Some(language) = language
12825                                    && language.name() == "Markdown".into()
12826                                {
12827                                    edit_for_markdown_paste(
12828                                        &snapshot,
12829                                        range,
12830                                        to_insert,
12831                                        url::Url::parse(to_insert).ok(),
12832                                    )
12833                                } else {
12834                                    (range, Cow::Borrowed(to_insert))
12835                                }
12836                            };
12837
12838                        edits.push((range, to_insert));
12839                        original_indent_columns.push(original_indent_column);
12840                    }
12841                    drop(snapshot);
12842
12843                    buffer.edit(
12844                        edits,
12845                        if auto_indent_on_paste {
12846                            Some(AutoindentMode::Block {
12847                                original_indent_columns,
12848                            })
12849                        } else {
12850                            None
12851                        },
12852                        cx,
12853                    );
12854                });
12855
12856                let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
12857                this.change_selections(Default::default(), window, cx, |s| s.select(selections));
12858            } else {
12859                let url = url::Url::parse(&clipboard_text).ok();
12860
12861                let auto_indent_mode = if !clipboard_text.is_empty() {
12862                    Some(AutoindentMode::Block {
12863                        original_indent_columns: Vec::new(),
12864                    })
12865                } else {
12866                    None
12867                };
12868
12869                let selection_anchors = this.buffer.update(cx, |buffer, cx| {
12870                    let snapshot = buffer.snapshot(cx);
12871
12872                    let anchors = old_selections
12873                        .iter()
12874                        .map(|s| {
12875                            let anchor = snapshot.anchor_after(s.head());
12876                            s.map(|_| anchor)
12877                        })
12878                        .collect::<Vec<_>>();
12879
12880                    let mut edits = Vec::new();
12881
12882                    for selection in old_selections.iter() {
12883                        let language = snapshot.language_at(selection.head());
12884                        let range = selection.range();
12885
12886                        let (edit_range, edit_text) = if let Some(language) = language
12887                            && language.name() == "Markdown".into()
12888                        {
12889                            edit_for_markdown_paste(&snapshot, range, &clipboard_text, url.clone())
12890                        } else {
12891                            (range, clipboard_text.clone())
12892                        };
12893
12894                        edits.push((edit_range, edit_text));
12895                    }
12896
12897                    drop(snapshot);
12898                    buffer.edit(edits, auto_indent_mode, cx);
12899
12900                    anchors
12901                });
12902
12903                this.change_selections(Default::default(), window, cx, |s| {
12904                    s.select_anchors(selection_anchors);
12905                });
12906            }
12907
12908            //   🤔                 |    ..     | show_in_menu |
12909            // | ..                  |   true        true
12910            // | had_edit_prediction |   false       true
12911
12912            let trigger_in_words =
12913                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
12914
12915            this.trigger_completion_on_input(text, trigger_in_words, window, cx);
12916        });
12917    }
12918
12919    pub fn diff_clipboard_with_selection(
12920        &mut self,
12921        _: &DiffClipboardWithSelection,
12922        window: &mut Window,
12923        cx: &mut Context<Self>,
12924    ) {
12925        let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
12926
12927        if selections.is_empty() {
12928            log::warn!("There should always be at least one selection in Zed. This is a bug.");
12929            return;
12930        };
12931
12932        let clipboard_text = match cx.read_from_clipboard() {
12933            Some(item) => match item.entries().first() {
12934                Some(ClipboardEntry::String(text)) => Some(text.text().to_string()),
12935                _ => None,
12936            },
12937            None => None,
12938        };
12939
12940        let Some(clipboard_text) = clipboard_text else {
12941            log::warn!("Clipboard doesn't contain text.");
12942            return;
12943        };
12944
12945        window.dispatch_action(
12946            Box::new(DiffClipboardWithSelectionData {
12947                clipboard_text,
12948                editor: cx.entity(),
12949            }),
12950            cx,
12951        );
12952    }
12953
12954    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
12955        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12956        if let Some(item) = cx.read_from_clipboard() {
12957            let entries = item.entries();
12958
12959            match entries.first() {
12960                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
12961                // of all the pasted entries.
12962                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
12963                    .do_paste(
12964                        clipboard_string.text(),
12965                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
12966                        true,
12967                        window,
12968                        cx,
12969                    ),
12970                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
12971            }
12972        }
12973    }
12974
12975    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
12976        if self.read_only(cx) {
12977            return;
12978        }
12979
12980        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12981
12982        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
12983            if let Some((selections, _)) =
12984                self.selection_history.transaction(transaction_id).cloned()
12985            {
12986                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12987                    s.select_anchors(selections.to_vec());
12988                });
12989            } else {
12990                log::error!(
12991                    "No entry in selection_history found for undo. \
12992                     This may correspond to a bug where undo does not update the selection. \
12993                     If this is occurring, please add details to \
12994                     https://github.com/zed-industries/zed/issues/22692"
12995                );
12996            }
12997            self.request_autoscroll(Autoscroll::fit(), cx);
12998            self.unmark_text(window, cx);
12999            self.refresh_edit_prediction(true, false, window, cx);
13000            cx.emit(EditorEvent::Edited { transaction_id });
13001            cx.emit(EditorEvent::TransactionUndone { transaction_id });
13002        }
13003    }
13004
13005    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
13006        if self.read_only(cx) {
13007            return;
13008        }
13009
13010        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13011
13012        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
13013            if let Some((_, Some(selections))) =
13014                self.selection_history.transaction(transaction_id).cloned()
13015            {
13016                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13017                    s.select_anchors(selections.to_vec());
13018                });
13019            } else {
13020                log::error!(
13021                    "No entry in selection_history found for redo. \
13022                     This may correspond to a bug where undo does not update the selection. \
13023                     If this is occurring, please add details to \
13024                     https://github.com/zed-industries/zed/issues/22692"
13025                );
13026            }
13027            self.request_autoscroll(Autoscroll::fit(), cx);
13028            self.unmark_text(window, cx);
13029            self.refresh_edit_prediction(true, false, window, cx);
13030            cx.emit(EditorEvent::Edited { transaction_id });
13031        }
13032    }
13033
13034    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
13035        self.buffer
13036            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
13037    }
13038
13039    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
13040        self.buffer
13041            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
13042    }
13043
13044    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
13045        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13046        self.change_selections(Default::default(), window, cx, |s| {
13047            s.move_with(|map, selection| {
13048                let cursor = if selection.is_empty() {
13049                    movement::left(map, selection.start)
13050                } else {
13051                    selection.start
13052                };
13053                selection.collapse_to(cursor, SelectionGoal::None);
13054            });
13055        })
13056    }
13057
13058    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
13059        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13060        self.change_selections(Default::default(), window, cx, |s| {
13061            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
13062        })
13063    }
13064
13065    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
13066        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13067        self.change_selections(Default::default(), window, cx, |s| {
13068            s.move_with(|map, selection| {
13069                let cursor = if selection.is_empty() {
13070                    movement::right(map, selection.end)
13071                } else {
13072                    selection.end
13073                };
13074                selection.collapse_to(cursor, SelectionGoal::None)
13075            });
13076        })
13077    }
13078
13079    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
13080        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13081        self.change_selections(Default::default(), window, cx, |s| {
13082            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
13083        });
13084    }
13085
13086    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
13087        if self.take_rename(true, window, cx).is_some() {
13088            return;
13089        }
13090
13091        if self.mode.is_single_line() {
13092            cx.propagate();
13093            return;
13094        }
13095
13096        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13097
13098        let text_layout_details = &self.text_layout_details(window);
13099        let selection_count = self.selections.count();
13100        let first_selection = self.selections.first_anchor();
13101
13102        self.change_selections(Default::default(), window, cx, |s| {
13103            s.move_with(|map, selection| {
13104                if !selection.is_empty() {
13105                    selection.goal = SelectionGoal::None;
13106                }
13107                let (cursor, goal) = movement::up(
13108                    map,
13109                    selection.start,
13110                    selection.goal,
13111                    false,
13112                    text_layout_details,
13113                );
13114                selection.collapse_to(cursor, goal);
13115            });
13116        });
13117
13118        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
13119        {
13120            cx.propagate();
13121        }
13122    }
13123
13124    pub fn move_up_by_lines(
13125        &mut self,
13126        action: &MoveUpByLines,
13127        window: &mut Window,
13128        cx: &mut Context<Self>,
13129    ) {
13130        if self.take_rename(true, window, cx).is_some() {
13131            return;
13132        }
13133
13134        if self.mode.is_single_line() {
13135            cx.propagate();
13136            return;
13137        }
13138
13139        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13140
13141        let text_layout_details = &self.text_layout_details(window);
13142
13143        self.change_selections(Default::default(), window, cx, |s| {
13144            s.move_with(|map, selection| {
13145                if !selection.is_empty() {
13146                    selection.goal = SelectionGoal::None;
13147                }
13148                let (cursor, goal) = movement::up_by_rows(
13149                    map,
13150                    selection.start,
13151                    action.lines,
13152                    selection.goal,
13153                    false,
13154                    text_layout_details,
13155                );
13156                selection.collapse_to(cursor, goal);
13157            });
13158        })
13159    }
13160
13161    pub fn move_down_by_lines(
13162        &mut self,
13163        action: &MoveDownByLines,
13164        window: &mut Window,
13165        cx: &mut Context<Self>,
13166    ) {
13167        if self.take_rename(true, window, cx).is_some() {
13168            return;
13169        }
13170
13171        if self.mode.is_single_line() {
13172            cx.propagate();
13173            return;
13174        }
13175
13176        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13177
13178        let text_layout_details = &self.text_layout_details(window);
13179
13180        self.change_selections(Default::default(), window, cx, |s| {
13181            s.move_with(|map, selection| {
13182                if !selection.is_empty() {
13183                    selection.goal = SelectionGoal::None;
13184                }
13185                let (cursor, goal) = movement::down_by_rows(
13186                    map,
13187                    selection.start,
13188                    action.lines,
13189                    selection.goal,
13190                    false,
13191                    text_layout_details,
13192                );
13193                selection.collapse_to(cursor, goal);
13194            });
13195        })
13196    }
13197
13198    pub fn select_down_by_lines(
13199        &mut self,
13200        action: &SelectDownByLines,
13201        window: &mut Window,
13202        cx: &mut Context<Self>,
13203    ) {
13204        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13205        let text_layout_details = &self.text_layout_details(window);
13206        self.change_selections(Default::default(), window, cx, |s| {
13207            s.move_heads_with(|map, head, goal| {
13208                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
13209            })
13210        })
13211    }
13212
13213    pub fn select_up_by_lines(
13214        &mut self,
13215        action: &SelectUpByLines,
13216        window: &mut Window,
13217        cx: &mut Context<Self>,
13218    ) {
13219        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13220        let text_layout_details = &self.text_layout_details(window);
13221        self.change_selections(Default::default(), window, cx, |s| {
13222            s.move_heads_with(|map, head, goal| {
13223                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
13224            })
13225        })
13226    }
13227
13228    pub fn select_page_up(
13229        &mut self,
13230        _: &SelectPageUp,
13231        window: &mut Window,
13232        cx: &mut Context<Self>,
13233    ) {
13234        let Some(row_count) = self.visible_row_count() else {
13235            return;
13236        };
13237
13238        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13239
13240        let text_layout_details = &self.text_layout_details(window);
13241
13242        self.change_selections(Default::default(), window, cx, |s| {
13243            s.move_heads_with(|map, head, goal| {
13244                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
13245            })
13246        })
13247    }
13248
13249    pub fn move_page_up(
13250        &mut self,
13251        action: &MovePageUp,
13252        window: &mut Window,
13253        cx: &mut Context<Self>,
13254    ) {
13255        if self.take_rename(true, window, cx).is_some() {
13256            return;
13257        }
13258
13259        if self
13260            .context_menu
13261            .borrow_mut()
13262            .as_mut()
13263            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
13264            .unwrap_or(false)
13265        {
13266            return;
13267        }
13268
13269        if matches!(self.mode, EditorMode::SingleLine) {
13270            cx.propagate();
13271            return;
13272        }
13273
13274        let Some(row_count) = self.visible_row_count() else {
13275            return;
13276        };
13277
13278        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13279
13280        let effects = if action.center_cursor {
13281            SelectionEffects::scroll(Autoscroll::center())
13282        } else {
13283            SelectionEffects::default()
13284        };
13285
13286        let text_layout_details = &self.text_layout_details(window);
13287
13288        self.change_selections(effects, window, cx, |s| {
13289            s.move_with(|map, selection| {
13290                if !selection.is_empty() {
13291                    selection.goal = SelectionGoal::None;
13292                }
13293                let (cursor, goal) = movement::up_by_rows(
13294                    map,
13295                    selection.end,
13296                    row_count,
13297                    selection.goal,
13298                    false,
13299                    text_layout_details,
13300                );
13301                selection.collapse_to(cursor, goal);
13302            });
13303        });
13304    }
13305
13306    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
13307        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13308        let text_layout_details = &self.text_layout_details(window);
13309        self.change_selections(Default::default(), window, cx, |s| {
13310            s.move_heads_with(|map, head, goal| {
13311                movement::up(map, head, goal, false, text_layout_details)
13312            })
13313        })
13314    }
13315
13316    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
13317        self.take_rename(true, window, cx);
13318
13319        if self.mode.is_single_line() {
13320            cx.propagate();
13321            return;
13322        }
13323
13324        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13325
13326        let text_layout_details = &self.text_layout_details(window);
13327        let selection_count = self.selections.count();
13328        let first_selection = self.selections.first_anchor();
13329
13330        self.change_selections(Default::default(), window, cx, |s| {
13331            s.move_with(|map, selection| {
13332                if !selection.is_empty() {
13333                    selection.goal = SelectionGoal::None;
13334                }
13335                let (cursor, goal) = movement::down(
13336                    map,
13337                    selection.end,
13338                    selection.goal,
13339                    false,
13340                    text_layout_details,
13341                );
13342                selection.collapse_to(cursor, goal);
13343            });
13344        });
13345
13346        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
13347        {
13348            cx.propagate();
13349        }
13350    }
13351
13352    pub fn select_page_down(
13353        &mut self,
13354        _: &SelectPageDown,
13355        window: &mut Window,
13356        cx: &mut Context<Self>,
13357    ) {
13358        let Some(row_count) = self.visible_row_count() else {
13359            return;
13360        };
13361
13362        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13363
13364        let text_layout_details = &self.text_layout_details(window);
13365
13366        self.change_selections(Default::default(), window, cx, |s| {
13367            s.move_heads_with(|map, head, goal| {
13368                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
13369            })
13370        })
13371    }
13372
13373    pub fn move_page_down(
13374        &mut self,
13375        action: &MovePageDown,
13376        window: &mut Window,
13377        cx: &mut Context<Self>,
13378    ) {
13379        if self.take_rename(true, window, cx).is_some() {
13380            return;
13381        }
13382
13383        if self
13384            .context_menu
13385            .borrow_mut()
13386            .as_mut()
13387            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
13388            .unwrap_or(false)
13389        {
13390            return;
13391        }
13392
13393        if matches!(self.mode, EditorMode::SingleLine) {
13394            cx.propagate();
13395            return;
13396        }
13397
13398        let Some(row_count) = self.visible_row_count() else {
13399            return;
13400        };
13401
13402        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13403
13404        let effects = if action.center_cursor {
13405            SelectionEffects::scroll(Autoscroll::center())
13406        } else {
13407            SelectionEffects::default()
13408        };
13409
13410        let text_layout_details = &self.text_layout_details(window);
13411        self.change_selections(effects, window, cx, |s| {
13412            s.move_with(|map, selection| {
13413                if !selection.is_empty() {
13414                    selection.goal = SelectionGoal::None;
13415                }
13416                let (cursor, goal) = movement::down_by_rows(
13417                    map,
13418                    selection.end,
13419                    row_count,
13420                    selection.goal,
13421                    false,
13422                    text_layout_details,
13423                );
13424                selection.collapse_to(cursor, goal);
13425            });
13426        });
13427    }
13428
13429    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
13430        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13431        let text_layout_details = &self.text_layout_details(window);
13432        self.change_selections(Default::default(), window, cx, |s| {
13433            s.move_heads_with(|map, head, goal| {
13434                movement::down(map, head, goal, false, text_layout_details)
13435            })
13436        });
13437    }
13438
13439    pub fn context_menu_first(
13440        &mut self,
13441        _: &ContextMenuFirst,
13442        window: &mut Window,
13443        cx: &mut Context<Self>,
13444    ) {
13445        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13446            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
13447        }
13448    }
13449
13450    pub fn context_menu_prev(
13451        &mut self,
13452        _: &ContextMenuPrevious,
13453        window: &mut Window,
13454        cx: &mut Context<Self>,
13455    ) {
13456        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13457            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
13458        }
13459    }
13460
13461    pub fn context_menu_next(
13462        &mut self,
13463        _: &ContextMenuNext,
13464        window: &mut Window,
13465        cx: &mut Context<Self>,
13466    ) {
13467        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13468            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
13469        }
13470    }
13471
13472    pub fn context_menu_last(
13473        &mut self,
13474        _: &ContextMenuLast,
13475        window: &mut Window,
13476        cx: &mut Context<Self>,
13477    ) {
13478        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13479            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
13480        }
13481    }
13482
13483    pub fn signature_help_prev(
13484        &mut self,
13485        _: &SignatureHelpPrevious,
13486        _: &mut Window,
13487        cx: &mut Context<Self>,
13488    ) {
13489        if let Some(popover) = self.signature_help_state.popover_mut() {
13490            if popover.current_signature == 0 {
13491                popover.current_signature = popover.signatures.len() - 1;
13492            } else {
13493                popover.current_signature -= 1;
13494            }
13495            cx.notify();
13496        }
13497    }
13498
13499    pub fn signature_help_next(
13500        &mut self,
13501        _: &SignatureHelpNext,
13502        _: &mut Window,
13503        cx: &mut Context<Self>,
13504    ) {
13505        if let Some(popover) = self.signature_help_state.popover_mut() {
13506            if popover.current_signature + 1 == popover.signatures.len() {
13507                popover.current_signature = 0;
13508            } else {
13509                popover.current_signature += 1;
13510            }
13511            cx.notify();
13512        }
13513    }
13514
13515    pub fn move_to_previous_word_start(
13516        &mut self,
13517        _: &MoveToPreviousWordStart,
13518        window: &mut Window,
13519        cx: &mut Context<Self>,
13520    ) {
13521        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13522        self.change_selections(Default::default(), window, cx, |s| {
13523            s.move_cursors_with(|map, head, _| {
13524                (
13525                    movement::previous_word_start(map, head),
13526                    SelectionGoal::None,
13527                )
13528            });
13529        })
13530    }
13531
13532    pub fn move_to_previous_subword_start(
13533        &mut self,
13534        _: &MoveToPreviousSubwordStart,
13535        window: &mut Window,
13536        cx: &mut Context<Self>,
13537    ) {
13538        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13539        self.change_selections(Default::default(), window, cx, |s| {
13540            s.move_cursors_with(|map, head, _| {
13541                (
13542                    movement::previous_subword_start(map, head),
13543                    SelectionGoal::None,
13544                )
13545            });
13546        })
13547    }
13548
13549    pub fn select_to_previous_word_start(
13550        &mut self,
13551        _: &SelectToPreviousWordStart,
13552        window: &mut Window,
13553        cx: &mut Context<Self>,
13554    ) {
13555        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13556        self.change_selections(Default::default(), window, cx, |s| {
13557            s.move_heads_with(|map, head, _| {
13558                (
13559                    movement::previous_word_start(map, head),
13560                    SelectionGoal::None,
13561                )
13562            });
13563        })
13564    }
13565
13566    pub fn select_to_previous_subword_start(
13567        &mut self,
13568        _: &SelectToPreviousSubwordStart,
13569        window: &mut Window,
13570        cx: &mut Context<Self>,
13571    ) {
13572        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13573        self.change_selections(Default::default(), window, cx, |s| {
13574            s.move_heads_with(|map, head, _| {
13575                (
13576                    movement::previous_subword_start(map, head),
13577                    SelectionGoal::None,
13578                )
13579            });
13580        })
13581    }
13582
13583    pub fn delete_to_previous_word_start(
13584        &mut self,
13585        action: &DeleteToPreviousWordStart,
13586        window: &mut Window,
13587        cx: &mut Context<Self>,
13588    ) {
13589        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13590        self.transact(window, cx, |this, window, cx| {
13591            this.select_autoclose_pair(window, cx);
13592            this.change_selections(Default::default(), window, cx, |s| {
13593                s.move_with(|map, selection| {
13594                    if selection.is_empty() {
13595                        let mut cursor = if action.ignore_newlines {
13596                            movement::previous_word_start(map, selection.head())
13597                        } else {
13598                            movement::previous_word_start_or_newline(map, selection.head())
13599                        };
13600                        cursor = movement::adjust_greedy_deletion(
13601                            map,
13602                            selection.head(),
13603                            cursor,
13604                            action.ignore_brackets,
13605                        );
13606                        selection.set_head(cursor, SelectionGoal::None);
13607                    }
13608                });
13609            });
13610            this.insert("", window, cx);
13611        });
13612    }
13613
13614    pub fn delete_to_previous_subword_start(
13615        &mut self,
13616        _: &DeleteToPreviousSubwordStart,
13617        window: &mut Window,
13618        cx: &mut Context<Self>,
13619    ) {
13620        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13621        self.transact(window, cx, |this, window, cx| {
13622            this.select_autoclose_pair(window, cx);
13623            this.change_selections(Default::default(), window, cx, |s| {
13624                s.move_with(|map, selection| {
13625                    if selection.is_empty() {
13626                        let mut cursor = movement::previous_subword_start(map, selection.head());
13627                        cursor =
13628                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13629                        selection.set_head(cursor, SelectionGoal::None);
13630                    }
13631                });
13632            });
13633            this.insert("", window, cx);
13634        });
13635    }
13636
13637    pub fn move_to_next_word_end(
13638        &mut self,
13639        _: &MoveToNextWordEnd,
13640        window: &mut Window,
13641        cx: &mut Context<Self>,
13642    ) {
13643        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13644        self.change_selections(Default::default(), window, cx, |s| {
13645            s.move_cursors_with(|map, head, _| {
13646                (movement::next_word_end(map, head), SelectionGoal::None)
13647            });
13648        })
13649    }
13650
13651    pub fn move_to_next_subword_end(
13652        &mut self,
13653        _: &MoveToNextSubwordEnd,
13654        window: &mut Window,
13655        cx: &mut Context<Self>,
13656    ) {
13657        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13658        self.change_selections(Default::default(), window, cx, |s| {
13659            s.move_cursors_with(|map, head, _| {
13660                (movement::next_subword_end(map, head), SelectionGoal::None)
13661            });
13662        })
13663    }
13664
13665    pub fn select_to_next_word_end(
13666        &mut self,
13667        _: &SelectToNextWordEnd,
13668        window: &mut Window,
13669        cx: &mut Context<Self>,
13670    ) {
13671        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13672        self.change_selections(Default::default(), window, cx, |s| {
13673            s.move_heads_with(|map, head, _| {
13674                (movement::next_word_end(map, head), SelectionGoal::None)
13675            });
13676        })
13677    }
13678
13679    pub fn select_to_next_subword_end(
13680        &mut self,
13681        _: &SelectToNextSubwordEnd,
13682        window: &mut Window,
13683        cx: &mut Context<Self>,
13684    ) {
13685        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13686        self.change_selections(Default::default(), window, cx, |s| {
13687            s.move_heads_with(|map, head, _| {
13688                (movement::next_subword_end(map, head), SelectionGoal::None)
13689            });
13690        })
13691    }
13692
13693    pub fn delete_to_next_word_end(
13694        &mut self,
13695        action: &DeleteToNextWordEnd,
13696        window: &mut Window,
13697        cx: &mut Context<Self>,
13698    ) {
13699        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13700        self.transact(window, cx, |this, window, cx| {
13701            this.change_selections(Default::default(), window, cx, |s| {
13702                s.move_with(|map, selection| {
13703                    if selection.is_empty() {
13704                        let mut cursor = if action.ignore_newlines {
13705                            movement::next_word_end(map, selection.head())
13706                        } else {
13707                            movement::next_word_end_or_newline(map, selection.head())
13708                        };
13709                        cursor = movement::adjust_greedy_deletion(
13710                            map,
13711                            selection.head(),
13712                            cursor,
13713                            action.ignore_brackets,
13714                        );
13715                        selection.set_head(cursor, SelectionGoal::None);
13716                    }
13717                });
13718            });
13719            this.insert("", window, cx);
13720        });
13721    }
13722
13723    pub fn delete_to_next_subword_end(
13724        &mut self,
13725        _: &DeleteToNextSubwordEnd,
13726        window: &mut Window,
13727        cx: &mut Context<Self>,
13728    ) {
13729        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13730        self.transact(window, cx, |this, window, cx| {
13731            this.change_selections(Default::default(), window, cx, |s| {
13732                s.move_with(|map, selection| {
13733                    if selection.is_empty() {
13734                        let mut cursor = movement::next_subword_end(map, selection.head());
13735                        cursor =
13736                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13737                        selection.set_head(cursor, SelectionGoal::None);
13738                    }
13739                });
13740            });
13741            this.insert("", window, cx);
13742        });
13743    }
13744
13745    pub fn move_to_beginning_of_line(
13746        &mut self,
13747        action: &MoveToBeginningOfLine,
13748        window: &mut Window,
13749        cx: &mut Context<Self>,
13750    ) {
13751        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13752        self.change_selections(Default::default(), window, cx, |s| {
13753            s.move_cursors_with(|map, head, _| {
13754                (
13755                    movement::indented_line_beginning(
13756                        map,
13757                        head,
13758                        action.stop_at_soft_wraps,
13759                        action.stop_at_indent,
13760                    ),
13761                    SelectionGoal::None,
13762                )
13763            });
13764        })
13765    }
13766
13767    pub fn select_to_beginning_of_line(
13768        &mut self,
13769        action: &SelectToBeginningOfLine,
13770        window: &mut Window,
13771        cx: &mut Context<Self>,
13772    ) {
13773        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13774        self.change_selections(Default::default(), window, cx, |s| {
13775            s.move_heads_with(|map, head, _| {
13776                (
13777                    movement::indented_line_beginning(
13778                        map,
13779                        head,
13780                        action.stop_at_soft_wraps,
13781                        action.stop_at_indent,
13782                    ),
13783                    SelectionGoal::None,
13784                )
13785            });
13786        });
13787    }
13788
13789    pub fn delete_to_beginning_of_line(
13790        &mut self,
13791        action: &DeleteToBeginningOfLine,
13792        window: &mut Window,
13793        cx: &mut Context<Self>,
13794    ) {
13795        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13796        self.transact(window, cx, |this, window, cx| {
13797            this.change_selections(Default::default(), window, cx, |s| {
13798                s.move_with(|_, selection| {
13799                    selection.reversed = true;
13800                });
13801            });
13802
13803            this.select_to_beginning_of_line(
13804                &SelectToBeginningOfLine {
13805                    stop_at_soft_wraps: false,
13806                    stop_at_indent: action.stop_at_indent,
13807                },
13808                window,
13809                cx,
13810            );
13811            this.backspace(&Backspace, window, cx);
13812        });
13813    }
13814
13815    pub fn move_to_end_of_line(
13816        &mut self,
13817        action: &MoveToEndOfLine,
13818        window: &mut Window,
13819        cx: &mut Context<Self>,
13820    ) {
13821        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13822        self.change_selections(Default::default(), window, cx, |s| {
13823            s.move_cursors_with(|map, head, _| {
13824                (
13825                    movement::line_end(map, head, action.stop_at_soft_wraps),
13826                    SelectionGoal::None,
13827                )
13828            });
13829        })
13830    }
13831
13832    pub fn select_to_end_of_line(
13833        &mut self,
13834        action: &SelectToEndOfLine,
13835        window: &mut Window,
13836        cx: &mut Context<Self>,
13837    ) {
13838        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13839        self.change_selections(Default::default(), window, cx, |s| {
13840            s.move_heads_with(|map, head, _| {
13841                (
13842                    movement::line_end(map, head, action.stop_at_soft_wraps),
13843                    SelectionGoal::None,
13844                )
13845            });
13846        })
13847    }
13848
13849    pub fn delete_to_end_of_line(
13850        &mut self,
13851        _: &DeleteToEndOfLine,
13852        window: &mut Window,
13853        cx: &mut Context<Self>,
13854    ) {
13855        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13856        self.transact(window, cx, |this, window, cx| {
13857            this.select_to_end_of_line(
13858                &SelectToEndOfLine {
13859                    stop_at_soft_wraps: false,
13860                },
13861                window,
13862                cx,
13863            );
13864            this.delete(&Delete, window, cx);
13865        });
13866    }
13867
13868    pub fn cut_to_end_of_line(
13869        &mut self,
13870        action: &CutToEndOfLine,
13871        window: &mut Window,
13872        cx: &mut Context<Self>,
13873    ) {
13874        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13875        self.transact(window, cx, |this, window, cx| {
13876            this.select_to_end_of_line(
13877                &SelectToEndOfLine {
13878                    stop_at_soft_wraps: false,
13879                },
13880                window,
13881                cx,
13882            );
13883            if !action.stop_at_newlines {
13884                this.change_selections(Default::default(), window, cx, |s| {
13885                    s.move_with(|_, sel| {
13886                        if sel.is_empty() {
13887                            sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
13888                        }
13889                    });
13890                });
13891            }
13892            this.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13893            let item = this.cut_common(false, window, cx);
13894            cx.write_to_clipboard(item);
13895        });
13896    }
13897
13898    pub fn move_to_start_of_paragraph(
13899        &mut self,
13900        _: &MoveToStartOfParagraph,
13901        window: &mut Window,
13902        cx: &mut Context<Self>,
13903    ) {
13904        if matches!(self.mode, EditorMode::SingleLine) {
13905            cx.propagate();
13906            return;
13907        }
13908        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13909        self.change_selections(Default::default(), window, cx, |s| {
13910            s.move_with(|map, selection| {
13911                selection.collapse_to(
13912                    movement::start_of_paragraph(map, selection.head(), 1),
13913                    SelectionGoal::None,
13914                )
13915            });
13916        })
13917    }
13918
13919    pub fn move_to_end_of_paragraph(
13920        &mut self,
13921        _: &MoveToEndOfParagraph,
13922        window: &mut Window,
13923        cx: &mut Context<Self>,
13924    ) {
13925        if matches!(self.mode, EditorMode::SingleLine) {
13926            cx.propagate();
13927            return;
13928        }
13929        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13930        self.change_selections(Default::default(), window, cx, |s| {
13931            s.move_with(|map, selection| {
13932                selection.collapse_to(
13933                    movement::end_of_paragraph(map, selection.head(), 1),
13934                    SelectionGoal::None,
13935                )
13936            });
13937        })
13938    }
13939
13940    pub fn select_to_start_of_paragraph(
13941        &mut self,
13942        _: &SelectToStartOfParagraph,
13943        window: &mut Window,
13944        cx: &mut Context<Self>,
13945    ) {
13946        if matches!(self.mode, EditorMode::SingleLine) {
13947            cx.propagate();
13948            return;
13949        }
13950        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13951        self.change_selections(Default::default(), window, cx, |s| {
13952            s.move_heads_with(|map, head, _| {
13953                (
13954                    movement::start_of_paragraph(map, head, 1),
13955                    SelectionGoal::None,
13956                )
13957            });
13958        })
13959    }
13960
13961    pub fn select_to_end_of_paragraph(
13962        &mut self,
13963        _: &SelectToEndOfParagraph,
13964        window: &mut Window,
13965        cx: &mut Context<Self>,
13966    ) {
13967        if matches!(self.mode, EditorMode::SingleLine) {
13968            cx.propagate();
13969            return;
13970        }
13971        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13972        self.change_selections(Default::default(), window, cx, |s| {
13973            s.move_heads_with(|map, head, _| {
13974                (
13975                    movement::end_of_paragraph(map, head, 1),
13976                    SelectionGoal::None,
13977                )
13978            });
13979        })
13980    }
13981
13982    pub fn move_to_start_of_excerpt(
13983        &mut self,
13984        _: &MoveToStartOfExcerpt,
13985        window: &mut Window,
13986        cx: &mut Context<Self>,
13987    ) {
13988        if matches!(self.mode, EditorMode::SingleLine) {
13989            cx.propagate();
13990            return;
13991        }
13992        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13993        self.change_selections(Default::default(), window, cx, |s| {
13994            s.move_with(|map, selection| {
13995                selection.collapse_to(
13996                    movement::start_of_excerpt(
13997                        map,
13998                        selection.head(),
13999                        workspace::searchable::Direction::Prev,
14000                    ),
14001                    SelectionGoal::None,
14002                )
14003            });
14004        })
14005    }
14006
14007    pub fn move_to_start_of_next_excerpt(
14008        &mut self,
14009        _: &MoveToStartOfNextExcerpt,
14010        window: &mut Window,
14011        cx: &mut Context<Self>,
14012    ) {
14013        if matches!(self.mode, EditorMode::SingleLine) {
14014            cx.propagate();
14015            return;
14016        }
14017
14018        self.change_selections(Default::default(), window, cx, |s| {
14019            s.move_with(|map, selection| {
14020                selection.collapse_to(
14021                    movement::start_of_excerpt(
14022                        map,
14023                        selection.head(),
14024                        workspace::searchable::Direction::Next,
14025                    ),
14026                    SelectionGoal::None,
14027                )
14028            });
14029        })
14030    }
14031
14032    pub fn move_to_end_of_excerpt(
14033        &mut self,
14034        _: &MoveToEndOfExcerpt,
14035        window: &mut Window,
14036        cx: &mut Context<Self>,
14037    ) {
14038        if matches!(self.mode, EditorMode::SingleLine) {
14039            cx.propagate();
14040            return;
14041        }
14042        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14043        self.change_selections(Default::default(), window, cx, |s| {
14044            s.move_with(|map, selection| {
14045                selection.collapse_to(
14046                    movement::end_of_excerpt(
14047                        map,
14048                        selection.head(),
14049                        workspace::searchable::Direction::Next,
14050                    ),
14051                    SelectionGoal::None,
14052                )
14053            });
14054        })
14055    }
14056
14057    pub fn move_to_end_of_previous_excerpt(
14058        &mut self,
14059        _: &MoveToEndOfPreviousExcerpt,
14060        window: &mut Window,
14061        cx: &mut Context<Self>,
14062    ) {
14063        if matches!(self.mode, EditorMode::SingleLine) {
14064            cx.propagate();
14065            return;
14066        }
14067        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14068        self.change_selections(Default::default(), window, cx, |s| {
14069            s.move_with(|map, selection| {
14070                selection.collapse_to(
14071                    movement::end_of_excerpt(
14072                        map,
14073                        selection.head(),
14074                        workspace::searchable::Direction::Prev,
14075                    ),
14076                    SelectionGoal::None,
14077                )
14078            });
14079        })
14080    }
14081
14082    pub fn select_to_start_of_excerpt(
14083        &mut self,
14084        _: &SelectToStartOfExcerpt,
14085        window: &mut Window,
14086        cx: &mut Context<Self>,
14087    ) {
14088        if matches!(self.mode, EditorMode::SingleLine) {
14089            cx.propagate();
14090            return;
14091        }
14092        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14093        self.change_selections(Default::default(), window, cx, |s| {
14094            s.move_heads_with(|map, head, _| {
14095                (
14096                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
14097                    SelectionGoal::None,
14098                )
14099            });
14100        })
14101    }
14102
14103    pub fn select_to_start_of_next_excerpt(
14104        &mut self,
14105        _: &SelectToStartOfNextExcerpt,
14106        window: &mut Window,
14107        cx: &mut Context<Self>,
14108    ) {
14109        if matches!(self.mode, EditorMode::SingleLine) {
14110            cx.propagate();
14111            return;
14112        }
14113        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14114        self.change_selections(Default::default(), window, cx, |s| {
14115            s.move_heads_with(|map, head, _| {
14116                (
14117                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
14118                    SelectionGoal::None,
14119                )
14120            });
14121        })
14122    }
14123
14124    pub fn select_to_end_of_excerpt(
14125        &mut self,
14126        _: &SelectToEndOfExcerpt,
14127        window: &mut Window,
14128        cx: &mut Context<Self>,
14129    ) {
14130        if matches!(self.mode, EditorMode::SingleLine) {
14131            cx.propagate();
14132            return;
14133        }
14134        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14135        self.change_selections(Default::default(), window, cx, |s| {
14136            s.move_heads_with(|map, head, _| {
14137                (
14138                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
14139                    SelectionGoal::None,
14140                )
14141            });
14142        })
14143    }
14144
14145    pub fn select_to_end_of_previous_excerpt(
14146        &mut self,
14147        _: &SelectToEndOfPreviousExcerpt,
14148        window: &mut Window,
14149        cx: &mut Context<Self>,
14150    ) {
14151        if matches!(self.mode, EditorMode::SingleLine) {
14152            cx.propagate();
14153            return;
14154        }
14155        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14156        self.change_selections(Default::default(), window, cx, |s| {
14157            s.move_heads_with(|map, head, _| {
14158                (
14159                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
14160                    SelectionGoal::None,
14161                )
14162            });
14163        })
14164    }
14165
14166    pub fn move_to_beginning(
14167        &mut self,
14168        _: &MoveToBeginning,
14169        window: &mut Window,
14170        cx: &mut Context<Self>,
14171    ) {
14172        if matches!(self.mode, EditorMode::SingleLine) {
14173            cx.propagate();
14174            return;
14175        }
14176        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14177        self.change_selections(Default::default(), window, cx, |s| {
14178            s.select_ranges(vec![0..0]);
14179        });
14180    }
14181
14182    pub fn select_to_beginning(
14183        &mut self,
14184        _: &SelectToBeginning,
14185        window: &mut Window,
14186        cx: &mut Context<Self>,
14187    ) {
14188        let mut selection = self.selections.last::<Point>(&self.display_snapshot(cx));
14189        selection.set_head(Point::zero(), SelectionGoal::None);
14190        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14191        self.change_selections(Default::default(), window, cx, |s| {
14192            s.select(vec![selection]);
14193        });
14194    }
14195
14196    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
14197        if matches!(self.mode, EditorMode::SingleLine) {
14198            cx.propagate();
14199            return;
14200        }
14201        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14202        let cursor = self.buffer.read(cx).read(cx).len();
14203        self.change_selections(Default::default(), window, cx, |s| {
14204            s.select_ranges(vec![cursor..cursor])
14205        });
14206    }
14207
14208    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
14209        self.nav_history = nav_history;
14210    }
14211
14212    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
14213        self.nav_history.as_ref()
14214    }
14215
14216    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
14217        self.push_to_nav_history(
14218            self.selections.newest_anchor().head(),
14219            None,
14220            false,
14221            true,
14222            cx,
14223        );
14224    }
14225
14226    fn push_to_nav_history(
14227        &mut self,
14228        cursor_anchor: Anchor,
14229        new_position: Option<Point>,
14230        is_deactivate: bool,
14231        always: bool,
14232        cx: &mut Context<Self>,
14233    ) {
14234        if let Some(nav_history) = self.nav_history.as_mut() {
14235            let buffer = self.buffer.read(cx).read(cx);
14236            let cursor_position = cursor_anchor.to_point(&buffer);
14237            let scroll_state = self.scroll_manager.anchor();
14238            let scroll_top_row = scroll_state.top_row(&buffer);
14239            drop(buffer);
14240
14241            if let Some(new_position) = new_position {
14242                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
14243                if row_delta == 0 || (row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA && !always) {
14244                    return;
14245                }
14246            }
14247
14248            nav_history.push(
14249                Some(NavigationData {
14250                    cursor_anchor,
14251                    cursor_position,
14252                    scroll_anchor: scroll_state,
14253                    scroll_top_row,
14254                }),
14255                cx,
14256            );
14257            cx.emit(EditorEvent::PushedToNavHistory {
14258                anchor: cursor_anchor,
14259                is_deactivate,
14260            })
14261        }
14262    }
14263
14264    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
14265        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14266        let buffer = self.buffer.read(cx).snapshot(cx);
14267        let mut selection = self.selections.first::<usize>(&self.display_snapshot(cx));
14268        selection.set_head(buffer.len(), SelectionGoal::None);
14269        self.change_selections(Default::default(), window, cx, |s| {
14270            s.select(vec![selection]);
14271        });
14272    }
14273
14274    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
14275        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14276        let end = self.buffer.read(cx).read(cx).len();
14277        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14278            s.select_ranges(vec![0..end]);
14279        });
14280    }
14281
14282    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
14283        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14284        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14285        let mut selections = self.selections.all::<Point>(&display_map);
14286        let max_point = display_map.buffer_snapshot().max_point();
14287        for selection in &mut selections {
14288            let rows = selection.spanned_rows(true, &display_map);
14289            selection.start = Point::new(rows.start.0, 0);
14290            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
14291            selection.reversed = false;
14292        }
14293        self.change_selections(Default::default(), window, cx, |s| {
14294            s.select(selections);
14295        });
14296    }
14297
14298    pub fn split_selection_into_lines(
14299        &mut self,
14300        action: &SplitSelectionIntoLines,
14301        window: &mut Window,
14302        cx: &mut Context<Self>,
14303    ) {
14304        let selections = self
14305            .selections
14306            .all::<Point>(&self.display_snapshot(cx))
14307            .into_iter()
14308            .map(|selection| selection.start..selection.end)
14309            .collect::<Vec<_>>();
14310        self.unfold_ranges(&selections, true, true, cx);
14311
14312        let mut new_selection_ranges = Vec::new();
14313        {
14314            let buffer = self.buffer.read(cx).read(cx);
14315            for selection in selections {
14316                for row in selection.start.row..selection.end.row {
14317                    let line_start = Point::new(row, 0);
14318                    let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
14319
14320                    if action.keep_selections {
14321                        // Keep the selection range for each line
14322                        let selection_start = if row == selection.start.row {
14323                            selection.start
14324                        } else {
14325                            line_start
14326                        };
14327                        new_selection_ranges.push(selection_start..line_end);
14328                    } else {
14329                        // Collapse to cursor at end of line
14330                        new_selection_ranges.push(line_end..line_end);
14331                    }
14332                }
14333
14334                let is_multiline_selection = selection.start.row != selection.end.row;
14335                // Don't insert last one if it's a multi-line selection ending at the start of a line,
14336                // so this action feels more ergonomic when paired with other selection operations
14337                let should_skip_last = is_multiline_selection && selection.end.column == 0;
14338                if !should_skip_last {
14339                    if action.keep_selections {
14340                        if is_multiline_selection {
14341                            let line_start = Point::new(selection.end.row, 0);
14342                            new_selection_ranges.push(line_start..selection.end);
14343                        } else {
14344                            new_selection_ranges.push(selection.start..selection.end);
14345                        }
14346                    } else {
14347                        new_selection_ranges.push(selection.end..selection.end);
14348                    }
14349                }
14350            }
14351        }
14352        self.change_selections(Default::default(), window, cx, |s| {
14353            s.select_ranges(new_selection_ranges);
14354        });
14355    }
14356
14357    pub fn add_selection_above(
14358        &mut self,
14359        action: &AddSelectionAbove,
14360        window: &mut Window,
14361        cx: &mut Context<Self>,
14362    ) {
14363        self.add_selection(true, action.skip_soft_wrap, window, cx);
14364    }
14365
14366    pub fn add_selection_below(
14367        &mut self,
14368        action: &AddSelectionBelow,
14369        window: &mut Window,
14370        cx: &mut Context<Self>,
14371    ) {
14372        self.add_selection(false, action.skip_soft_wrap, window, cx);
14373    }
14374
14375    fn add_selection(
14376        &mut self,
14377        above: bool,
14378        skip_soft_wrap: bool,
14379        window: &mut Window,
14380        cx: &mut Context<Self>,
14381    ) {
14382        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14383
14384        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14385        let all_selections = self.selections.all::<Point>(&display_map);
14386        let text_layout_details = self.text_layout_details(window);
14387
14388        let (mut columnar_selections, new_selections_to_columnarize) = {
14389            if let Some(state) = self.add_selections_state.as_ref() {
14390                let columnar_selection_ids: HashSet<_> = state
14391                    .groups
14392                    .iter()
14393                    .flat_map(|group| group.stack.iter())
14394                    .copied()
14395                    .collect();
14396
14397                all_selections
14398                    .into_iter()
14399                    .partition(|s| columnar_selection_ids.contains(&s.id))
14400            } else {
14401                (Vec::new(), all_selections)
14402            }
14403        };
14404
14405        let mut state = self
14406            .add_selections_state
14407            .take()
14408            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
14409
14410        for selection in new_selections_to_columnarize {
14411            let range = selection.display_range(&display_map).sorted();
14412            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
14413            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
14414            let positions = start_x.min(end_x)..start_x.max(end_x);
14415            let mut stack = Vec::new();
14416            for row in range.start.row().0..=range.end.row().0 {
14417                if let Some(selection) = self.selections.build_columnar_selection(
14418                    &display_map,
14419                    DisplayRow(row),
14420                    &positions,
14421                    selection.reversed,
14422                    &text_layout_details,
14423                ) {
14424                    stack.push(selection.id);
14425                    columnar_selections.push(selection);
14426                }
14427            }
14428            if !stack.is_empty() {
14429                if above {
14430                    stack.reverse();
14431                }
14432                state.groups.push(AddSelectionsGroup { above, stack });
14433            }
14434        }
14435
14436        let mut final_selections = Vec::new();
14437        let end_row = if above {
14438            DisplayRow(0)
14439        } else {
14440            display_map.max_point().row()
14441        };
14442
14443        let mut last_added_item_per_group = HashMap::default();
14444        for group in state.groups.iter_mut() {
14445            if let Some(last_id) = group.stack.last() {
14446                last_added_item_per_group.insert(*last_id, group);
14447            }
14448        }
14449
14450        for selection in columnar_selections {
14451            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
14452                if above == group.above {
14453                    let range = selection.display_range(&display_map).sorted();
14454                    debug_assert_eq!(range.start.row(), range.end.row());
14455                    let mut row = range.start.row();
14456                    let positions =
14457                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
14458                            Pixels::from(start)..Pixels::from(end)
14459                        } else {
14460                            let start_x =
14461                                display_map.x_for_display_point(range.start, &text_layout_details);
14462                            let end_x =
14463                                display_map.x_for_display_point(range.end, &text_layout_details);
14464                            start_x.min(end_x)..start_x.max(end_x)
14465                        };
14466
14467                    let mut maybe_new_selection = None;
14468                    let direction = if above { -1 } else { 1 };
14469
14470                    while row != end_row {
14471                        if skip_soft_wrap {
14472                            row = display_map
14473                                .start_of_relative_buffer_row(DisplayPoint::new(row, 0), direction)
14474                                .row();
14475                        } else if above {
14476                            row.0 -= 1;
14477                        } else {
14478                            row.0 += 1;
14479                        }
14480
14481                        if let Some(new_selection) = self.selections.build_columnar_selection(
14482                            &display_map,
14483                            row,
14484                            &positions,
14485                            selection.reversed,
14486                            &text_layout_details,
14487                        ) {
14488                            maybe_new_selection = Some(new_selection);
14489                            break;
14490                        }
14491                    }
14492
14493                    if let Some(new_selection) = maybe_new_selection {
14494                        group.stack.push(new_selection.id);
14495                        if above {
14496                            final_selections.push(new_selection);
14497                            final_selections.push(selection);
14498                        } else {
14499                            final_selections.push(selection);
14500                            final_selections.push(new_selection);
14501                        }
14502                    } else {
14503                        final_selections.push(selection);
14504                    }
14505                } else {
14506                    group.stack.pop();
14507                }
14508            } else {
14509                final_selections.push(selection);
14510            }
14511        }
14512
14513        self.change_selections(Default::default(), window, cx, |s| {
14514            s.select(final_selections);
14515        });
14516
14517        let final_selection_ids: HashSet<_> = self
14518            .selections
14519            .all::<Point>(&display_map)
14520            .iter()
14521            .map(|s| s.id)
14522            .collect();
14523        state.groups.retain_mut(|group| {
14524            // selections might get merged above so we remove invalid items from stacks
14525            group.stack.retain(|id| final_selection_ids.contains(id));
14526
14527            // single selection in stack can be treated as initial state
14528            group.stack.len() > 1
14529        });
14530
14531        if !state.groups.is_empty() {
14532            self.add_selections_state = Some(state);
14533        }
14534    }
14535
14536    fn select_match_ranges(
14537        &mut self,
14538        range: Range<usize>,
14539        reversed: bool,
14540        replace_newest: bool,
14541        auto_scroll: Option<Autoscroll>,
14542        window: &mut Window,
14543        cx: &mut Context<Editor>,
14544    ) {
14545        self.unfold_ranges(
14546            std::slice::from_ref(&range),
14547            false,
14548            auto_scroll.is_some(),
14549            cx,
14550        );
14551        let effects = if let Some(scroll) = auto_scroll {
14552            SelectionEffects::scroll(scroll)
14553        } else {
14554            SelectionEffects::no_scroll()
14555        };
14556        self.change_selections(effects, window, cx, |s| {
14557            if replace_newest {
14558                s.delete(s.newest_anchor().id);
14559            }
14560            if reversed {
14561                s.insert_range(range.end..range.start);
14562            } else {
14563                s.insert_range(range);
14564            }
14565        });
14566    }
14567
14568    pub fn select_next_match_internal(
14569        &mut self,
14570        display_map: &DisplaySnapshot,
14571        replace_newest: bool,
14572        autoscroll: Option<Autoscroll>,
14573        window: &mut Window,
14574        cx: &mut Context<Self>,
14575    ) -> Result<()> {
14576        let buffer = display_map.buffer_snapshot();
14577        let mut selections = self.selections.all::<usize>(&display_map);
14578        if let Some(mut select_next_state) = self.select_next_state.take() {
14579            let query = &select_next_state.query;
14580            if !select_next_state.done {
14581                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14582                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14583                let mut next_selected_range = None;
14584
14585                let bytes_after_last_selection =
14586                    buffer.bytes_in_range(last_selection.end..buffer.len());
14587                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
14588                let query_matches = query
14589                    .stream_find_iter(bytes_after_last_selection)
14590                    .map(|result| (last_selection.end, result))
14591                    .chain(
14592                        query
14593                            .stream_find_iter(bytes_before_first_selection)
14594                            .map(|result| (0, result)),
14595                    );
14596
14597                for (start_offset, query_match) in query_matches {
14598                    let query_match = query_match.unwrap(); // can only fail due to I/O
14599                    let offset_range =
14600                        start_offset + query_match.start()..start_offset + query_match.end();
14601
14602                    if !select_next_state.wordwise
14603                        || (!buffer.is_inside_word(offset_range.start, None)
14604                            && !buffer.is_inside_word(offset_range.end, None))
14605                    {
14606                        let idx = selections
14607                            .partition_point(|selection| selection.end <= offset_range.start);
14608                        let overlaps = selections
14609                            .get(idx)
14610                            .map_or(false, |selection| selection.start < offset_range.end);
14611
14612                        if !overlaps {
14613                            next_selected_range = Some(offset_range);
14614                            break;
14615                        }
14616                    }
14617                }
14618
14619                if let Some(next_selected_range) = next_selected_range {
14620                    self.select_match_ranges(
14621                        next_selected_range,
14622                        last_selection.reversed,
14623                        replace_newest,
14624                        autoscroll,
14625                        window,
14626                        cx,
14627                    );
14628                } else {
14629                    select_next_state.done = true;
14630                }
14631            }
14632
14633            self.select_next_state = Some(select_next_state);
14634        } else {
14635            let mut only_carets = true;
14636            let mut same_text_selected = true;
14637            let mut selected_text = None;
14638
14639            let mut selections_iter = selections.iter().peekable();
14640            while let Some(selection) = selections_iter.next() {
14641                if selection.start != selection.end {
14642                    only_carets = false;
14643                }
14644
14645                if same_text_selected {
14646                    if selected_text.is_none() {
14647                        selected_text =
14648                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14649                    }
14650
14651                    if let Some(next_selection) = selections_iter.peek() {
14652                        if next_selection.range().len() == selection.range().len() {
14653                            let next_selected_text = buffer
14654                                .text_for_range(next_selection.range())
14655                                .collect::<String>();
14656                            if Some(next_selected_text) != selected_text {
14657                                same_text_selected = false;
14658                                selected_text = None;
14659                            }
14660                        } else {
14661                            same_text_selected = false;
14662                            selected_text = None;
14663                        }
14664                    }
14665                }
14666            }
14667
14668            if only_carets {
14669                for selection in &mut selections {
14670                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
14671                    selection.start = word_range.start;
14672                    selection.end = word_range.end;
14673                    selection.goal = SelectionGoal::None;
14674                    selection.reversed = false;
14675                    self.select_match_ranges(
14676                        selection.start..selection.end,
14677                        selection.reversed,
14678                        replace_newest,
14679                        autoscroll,
14680                        window,
14681                        cx,
14682                    );
14683                }
14684
14685                if selections.len() == 1 {
14686                    let selection = selections
14687                        .last()
14688                        .expect("ensured that there's only one selection");
14689                    let query = buffer
14690                        .text_for_range(selection.start..selection.end)
14691                        .collect::<String>();
14692                    let is_empty = query.is_empty();
14693                    let select_state = SelectNextState {
14694                        query: self.build_query(&[query], cx)?,
14695                        wordwise: true,
14696                        done: is_empty,
14697                    };
14698                    self.select_next_state = Some(select_state);
14699                } else {
14700                    self.select_next_state = None;
14701                }
14702            } else if let Some(selected_text) = selected_text {
14703                self.select_next_state = Some(SelectNextState {
14704                    query: self.build_query(&[selected_text], cx)?,
14705                    wordwise: false,
14706                    done: false,
14707                });
14708                self.select_next_match_internal(
14709                    display_map,
14710                    replace_newest,
14711                    autoscroll,
14712                    window,
14713                    cx,
14714                )?;
14715            }
14716        }
14717        Ok(())
14718    }
14719
14720    pub fn select_all_matches(
14721        &mut self,
14722        _action: &SelectAllMatches,
14723        window: &mut Window,
14724        cx: &mut Context<Self>,
14725    ) -> Result<()> {
14726        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14727
14728        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14729
14730        self.select_next_match_internal(&display_map, false, None, window, cx)?;
14731        let Some(select_next_state) = self.select_next_state.as_mut() else {
14732            return Ok(());
14733        };
14734        if select_next_state.done {
14735            return Ok(());
14736        }
14737
14738        let mut new_selections = Vec::new();
14739
14740        let reversed = self.selections.oldest::<usize>(&display_map).reversed;
14741        let buffer = display_map.buffer_snapshot();
14742        let query_matches = select_next_state
14743            .query
14744            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
14745
14746        for query_match in query_matches.into_iter() {
14747            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
14748            let offset_range = if reversed {
14749                query_match.end()..query_match.start()
14750            } else {
14751                query_match.start()..query_match.end()
14752            };
14753
14754            if !select_next_state.wordwise
14755                || (!buffer.is_inside_word(offset_range.start, None)
14756                    && !buffer.is_inside_word(offset_range.end, None))
14757            {
14758                new_selections.push(offset_range.start..offset_range.end);
14759            }
14760        }
14761
14762        select_next_state.done = true;
14763
14764        if new_selections.is_empty() {
14765            log::error!("bug: new_selections is empty in select_all_matches");
14766            return Ok(());
14767        }
14768
14769        self.unfold_ranges(&new_selections.clone(), false, false, cx);
14770        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
14771            selections.select_ranges(new_selections)
14772        });
14773
14774        Ok(())
14775    }
14776
14777    pub fn select_next(
14778        &mut self,
14779        action: &SelectNext,
14780        window: &mut Window,
14781        cx: &mut Context<Self>,
14782    ) -> Result<()> {
14783        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14784        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14785        self.select_next_match_internal(
14786            &display_map,
14787            action.replace_newest,
14788            Some(Autoscroll::newest()),
14789            window,
14790            cx,
14791        )?;
14792        Ok(())
14793    }
14794
14795    pub fn select_previous(
14796        &mut self,
14797        action: &SelectPrevious,
14798        window: &mut Window,
14799        cx: &mut Context<Self>,
14800    ) -> Result<()> {
14801        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14802        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14803        let buffer = display_map.buffer_snapshot();
14804        let mut selections = self.selections.all::<usize>(&display_map);
14805        if let Some(mut select_prev_state) = self.select_prev_state.take() {
14806            let query = &select_prev_state.query;
14807            if !select_prev_state.done {
14808                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14809                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14810                let mut next_selected_range = None;
14811                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
14812                let bytes_before_last_selection =
14813                    buffer.reversed_bytes_in_range(0..last_selection.start);
14814                let bytes_after_first_selection =
14815                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
14816                let query_matches = query
14817                    .stream_find_iter(bytes_before_last_selection)
14818                    .map(|result| (last_selection.start, result))
14819                    .chain(
14820                        query
14821                            .stream_find_iter(bytes_after_first_selection)
14822                            .map(|result| (buffer.len(), result)),
14823                    );
14824                for (end_offset, query_match) in query_matches {
14825                    let query_match = query_match.unwrap(); // can only fail due to I/O
14826                    let offset_range =
14827                        end_offset - query_match.end()..end_offset - query_match.start();
14828
14829                    if !select_prev_state.wordwise
14830                        || (!buffer.is_inside_word(offset_range.start, None)
14831                            && !buffer.is_inside_word(offset_range.end, None))
14832                    {
14833                        next_selected_range = Some(offset_range);
14834                        break;
14835                    }
14836                }
14837
14838                if let Some(next_selected_range) = next_selected_range {
14839                    self.select_match_ranges(
14840                        next_selected_range,
14841                        last_selection.reversed,
14842                        action.replace_newest,
14843                        Some(Autoscroll::newest()),
14844                        window,
14845                        cx,
14846                    );
14847                } else {
14848                    select_prev_state.done = true;
14849                }
14850            }
14851
14852            self.select_prev_state = Some(select_prev_state);
14853        } else {
14854            let mut only_carets = true;
14855            let mut same_text_selected = true;
14856            let mut selected_text = None;
14857
14858            let mut selections_iter = selections.iter().peekable();
14859            while let Some(selection) = selections_iter.next() {
14860                if selection.start != selection.end {
14861                    only_carets = false;
14862                }
14863
14864                if same_text_selected {
14865                    if selected_text.is_none() {
14866                        selected_text =
14867                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14868                    }
14869
14870                    if let Some(next_selection) = selections_iter.peek() {
14871                        if next_selection.range().len() == selection.range().len() {
14872                            let next_selected_text = buffer
14873                                .text_for_range(next_selection.range())
14874                                .collect::<String>();
14875                            if Some(next_selected_text) != selected_text {
14876                                same_text_selected = false;
14877                                selected_text = None;
14878                            }
14879                        } else {
14880                            same_text_selected = false;
14881                            selected_text = None;
14882                        }
14883                    }
14884                }
14885            }
14886
14887            if only_carets {
14888                for selection in &mut selections {
14889                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
14890                    selection.start = word_range.start;
14891                    selection.end = word_range.end;
14892                    selection.goal = SelectionGoal::None;
14893                    selection.reversed = false;
14894                    self.select_match_ranges(
14895                        selection.start..selection.end,
14896                        selection.reversed,
14897                        action.replace_newest,
14898                        Some(Autoscroll::newest()),
14899                        window,
14900                        cx,
14901                    );
14902                }
14903                if selections.len() == 1 {
14904                    let selection = selections
14905                        .last()
14906                        .expect("ensured that there's only one selection");
14907                    let query = buffer
14908                        .text_for_range(selection.start..selection.end)
14909                        .collect::<String>();
14910                    let is_empty = query.is_empty();
14911                    let select_state = SelectNextState {
14912                        query: self.build_query(&[query.chars().rev().collect::<String>()], cx)?,
14913                        wordwise: true,
14914                        done: is_empty,
14915                    };
14916                    self.select_prev_state = Some(select_state);
14917                } else {
14918                    self.select_prev_state = None;
14919                }
14920            } else if let Some(selected_text) = selected_text {
14921                self.select_prev_state = Some(SelectNextState {
14922                    query: self
14923                        .build_query(&[selected_text.chars().rev().collect::<String>()], cx)?,
14924                    wordwise: false,
14925                    done: false,
14926                });
14927                self.select_previous(action, window, cx)?;
14928            }
14929        }
14930        Ok(())
14931    }
14932
14933    /// Builds an `AhoCorasick` automaton from the provided patterns, while
14934    /// setting the case sensitivity based on the global
14935    /// `SelectNextCaseSensitive` setting, if set, otherwise based on the
14936    /// editor's settings.
14937    fn build_query<I, P>(&self, patterns: I, cx: &Context<Self>) -> Result<AhoCorasick, BuildError>
14938    where
14939        I: IntoIterator<Item = P>,
14940        P: AsRef<[u8]>,
14941    {
14942        let case_sensitive = self.select_next_is_case_sensitive.map_or_else(
14943            || EditorSettings::get_global(cx).search.case_sensitive,
14944            |value| value,
14945        );
14946
14947        let mut builder = AhoCorasickBuilder::new();
14948        builder.ascii_case_insensitive(!case_sensitive);
14949        builder.build(patterns)
14950    }
14951
14952    pub fn find_next_match(
14953        &mut self,
14954        _: &FindNextMatch,
14955        window: &mut Window,
14956        cx: &mut Context<Self>,
14957    ) -> Result<()> {
14958        let selections = self.selections.disjoint_anchors_arc();
14959        match selections.first() {
14960            Some(first) if selections.len() >= 2 => {
14961                self.change_selections(Default::default(), window, cx, |s| {
14962                    s.select_ranges([first.range()]);
14963                });
14964            }
14965            _ => self.select_next(
14966                &SelectNext {
14967                    replace_newest: true,
14968                },
14969                window,
14970                cx,
14971            )?,
14972        }
14973        Ok(())
14974    }
14975
14976    pub fn find_previous_match(
14977        &mut self,
14978        _: &FindPreviousMatch,
14979        window: &mut Window,
14980        cx: &mut Context<Self>,
14981    ) -> Result<()> {
14982        let selections = self.selections.disjoint_anchors_arc();
14983        match selections.last() {
14984            Some(last) if selections.len() >= 2 => {
14985                self.change_selections(Default::default(), window, cx, |s| {
14986                    s.select_ranges([last.range()]);
14987                });
14988            }
14989            _ => self.select_previous(
14990                &SelectPrevious {
14991                    replace_newest: true,
14992                },
14993                window,
14994                cx,
14995            )?,
14996        }
14997        Ok(())
14998    }
14999
15000    pub fn toggle_comments(
15001        &mut self,
15002        action: &ToggleComments,
15003        window: &mut Window,
15004        cx: &mut Context<Self>,
15005    ) {
15006        if self.read_only(cx) {
15007            return;
15008        }
15009        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
15010        let text_layout_details = &self.text_layout_details(window);
15011        self.transact(window, cx, |this, window, cx| {
15012            let mut selections = this
15013                .selections
15014                .all::<MultiBufferPoint>(&this.display_snapshot(cx));
15015            let mut edits = Vec::new();
15016            let mut selection_edit_ranges = Vec::new();
15017            let mut last_toggled_row = None;
15018            let snapshot = this.buffer.read(cx).read(cx);
15019            let empty_str: Arc<str> = Arc::default();
15020            let mut suffixes_inserted = Vec::new();
15021            let ignore_indent = action.ignore_indent;
15022
15023            fn comment_prefix_range(
15024                snapshot: &MultiBufferSnapshot,
15025                row: MultiBufferRow,
15026                comment_prefix: &str,
15027                comment_prefix_whitespace: &str,
15028                ignore_indent: bool,
15029            ) -> Range<Point> {
15030                let indent_size = if ignore_indent {
15031                    0
15032                } else {
15033                    snapshot.indent_size_for_line(row).len
15034                };
15035
15036                let start = Point::new(row.0, indent_size);
15037
15038                let mut line_bytes = snapshot
15039                    .bytes_in_range(start..snapshot.max_point())
15040                    .flatten()
15041                    .copied();
15042
15043                // If this line currently begins with the line comment prefix, then record
15044                // the range containing the prefix.
15045                if line_bytes
15046                    .by_ref()
15047                    .take(comment_prefix.len())
15048                    .eq(comment_prefix.bytes())
15049                {
15050                    // Include any whitespace that matches the comment prefix.
15051                    let matching_whitespace_len = line_bytes
15052                        .zip(comment_prefix_whitespace.bytes())
15053                        .take_while(|(a, b)| a == b)
15054                        .count() as u32;
15055                    let end = Point::new(
15056                        start.row,
15057                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
15058                    );
15059                    start..end
15060                } else {
15061                    start..start
15062                }
15063            }
15064
15065            fn comment_suffix_range(
15066                snapshot: &MultiBufferSnapshot,
15067                row: MultiBufferRow,
15068                comment_suffix: &str,
15069                comment_suffix_has_leading_space: bool,
15070            ) -> Range<Point> {
15071                let end = Point::new(row.0, snapshot.line_len(row));
15072                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
15073
15074                let mut line_end_bytes = snapshot
15075                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
15076                    .flatten()
15077                    .copied();
15078
15079                let leading_space_len = if suffix_start_column > 0
15080                    && line_end_bytes.next() == Some(b' ')
15081                    && comment_suffix_has_leading_space
15082                {
15083                    1
15084                } else {
15085                    0
15086                };
15087
15088                // If this line currently begins with the line comment prefix, then record
15089                // the range containing the prefix.
15090                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
15091                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
15092                    start..end
15093                } else {
15094                    end..end
15095                }
15096            }
15097
15098            // TODO: Handle selections that cross excerpts
15099            for selection in &mut selections {
15100                let start_column = snapshot
15101                    .indent_size_for_line(MultiBufferRow(selection.start.row))
15102                    .len;
15103                let language = if let Some(language) =
15104                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
15105                {
15106                    language
15107                } else {
15108                    continue;
15109                };
15110
15111                selection_edit_ranges.clear();
15112
15113                // If multiple selections contain a given row, avoid processing that
15114                // row more than once.
15115                let mut start_row = MultiBufferRow(selection.start.row);
15116                if last_toggled_row == Some(start_row) {
15117                    start_row = start_row.next_row();
15118                }
15119                let end_row =
15120                    if selection.end.row > selection.start.row && selection.end.column == 0 {
15121                        MultiBufferRow(selection.end.row - 1)
15122                    } else {
15123                        MultiBufferRow(selection.end.row)
15124                    };
15125                last_toggled_row = Some(end_row);
15126
15127                if start_row > end_row {
15128                    continue;
15129                }
15130
15131                // If the language has line comments, toggle those.
15132                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
15133
15134                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
15135                if ignore_indent {
15136                    full_comment_prefixes = full_comment_prefixes
15137                        .into_iter()
15138                        .map(|s| Arc::from(s.trim_end()))
15139                        .collect();
15140                }
15141
15142                if !full_comment_prefixes.is_empty() {
15143                    let first_prefix = full_comment_prefixes
15144                        .first()
15145                        .expect("prefixes is non-empty");
15146                    let prefix_trimmed_lengths = full_comment_prefixes
15147                        .iter()
15148                        .map(|p| p.trim_end_matches(' ').len())
15149                        .collect::<SmallVec<[usize; 4]>>();
15150
15151                    let mut all_selection_lines_are_comments = true;
15152
15153                    for row in start_row.0..=end_row.0 {
15154                        let row = MultiBufferRow(row);
15155                        if start_row < end_row && snapshot.is_line_blank(row) {
15156                            continue;
15157                        }
15158
15159                        let prefix_range = full_comment_prefixes
15160                            .iter()
15161                            .zip(prefix_trimmed_lengths.iter().copied())
15162                            .map(|(prefix, trimmed_prefix_len)| {
15163                                comment_prefix_range(
15164                                    snapshot.deref(),
15165                                    row,
15166                                    &prefix[..trimmed_prefix_len],
15167                                    &prefix[trimmed_prefix_len..],
15168                                    ignore_indent,
15169                                )
15170                            })
15171                            .max_by_key(|range| range.end.column - range.start.column)
15172                            .expect("prefixes is non-empty");
15173
15174                        if prefix_range.is_empty() {
15175                            all_selection_lines_are_comments = false;
15176                        }
15177
15178                        selection_edit_ranges.push(prefix_range);
15179                    }
15180
15181                    if all_selection_lines_are_comments {
15182                        edits.extend(
15183                            selection_edit_ranges
15184                                .iter()
15185                                .cloned()
15186                                .map(|range| (range, empty_str.clone())),
15187                        );
15188                    } else {
15189                        let min_column = selection_edit_ranges
15190                            .iter()
15191                            .map(|range| range.start.column)
15192                            .min()
15193                            .unwrap_or(0);
15194                        edits.extend(selection_edit_ranges.iter().map(|range| {
15195                            let position = Point::new(range.start.row, min_column);
15196                            (position..position, first_prefix.clone())
15197                        }));
15198                    }
15199                } else if let Some(BlockCommentConfig {
15200                    start: full_comment_prefix,
15201                    end: comment_suffix,
15202                    ..
15203                }) = language.block_comment()
15204                {
15205                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
15206                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
15207                    let prefix_range = comment_prefix_range(
15208                        snapshot.deref(),
15209                        start_row,
15210                        comment_prefix,
15211                        comment_prefix_whitespace,
15212                        ignore_indent,
15213                    );
15214                    let suffix_range = comment_suffix_range(
15215                        snapshot.deref(),
15216                        end_row,
15217                        comment_suffix.trim_start_matches(' '),
15218                        comment_suffix.starts_with(' '),
15219                    );
15220
15221                    if prefix_range.is_empty() || suffix_range.is_empty() {
15222                        edits.push((
15223                            prefix_range.start..prefix_range.start,
15224                            full_comment_prefix.clone(),
15225                        ));
15226                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
15227                        suffixes_inserted.push((end_row, comment_suffix.len()));
15228                    } else {
15229                        edits.push((prefix_range, empty_str.clone()));
15230                        edits.push((suffix_range, empty_str.clone()));
15231                    }
15232                } else {
15233                    continue;
15234                }
15235            }
15236
15237            drop(snapshot);
15238            this.buffer.update(cx, |buffer, cx| {
15239                buffer.edit(edits, None, cx);
15240            });
15241
15242            // Adjust selections so that they end before any comment suffixes that
15243            // were inserted.
15244            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
15245            let mut selections = this.selections.all::<Point>(&this.display_snapshot(cx));
15246            let snapshot = this.buffer.read(cx).read(cx);
15247            for selection in &mut selections {
15248                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
15249                    match row.cmp(&MultiBufferRow(selection.end.row)) {
15250                        Ordering::Less => {
15251                            suffixes_inserted.next();
15252                            continue;
15253                        }
15254                        Ordering::Greater => break,
15255                        Ordering::Equal => {
15256                            if selection.end.column == snapshot.line_len(row) {
15257                                if selection.is_empty() {
15258                                    selection.start.column -= suffix_len as u32;
15259                                }
15260                                selection.end.column -= suffix_len as u32;
15261                            }
15262                            break;
15263                        }
15264                    }
15265                }
15266            }
15267
15268            drop(snapshot);
15269            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
15270
15271            let selections = this.selections.all::<Point>(&this.display_snapshot(cx));
15272            let selections_on_single_row = selections.windows(2).all(|selections| {
15273                selections[0].start.row == selections[1].start.row
15274                    && selections[0].end.row == selections[1].end.row
15275                    && selections[0].start.row == selections[0].end.row
15276            });
15277            let selections_selecting = selections
15278                .iter()
15279                .any(|selection| selection.start != selection.end);
15280            let advance_downwards = action.advance_downwards
15281                && selections_on_single_row
15282                && !selections_selecting
15283                && !matches!(this.mode, EditorMode::SingleLine);
15284
15285            if advance_downwards {
15286                let snapshot = this.buffer.read(cx).snapshot(cx);
15287
15288                this.change_selections(Default::default(), window, cx, |s| {
15289                    s.move_cursors_with(|display_snapshot, display_point, _| {
15290                        let mut point = display_point.to_point(display_snapshot);
15291                        point.row += 1;
15292                        point = snapshot.clip_point(point, Bias::Left);
15293                        let display_point = point.to_display_point(display_snapshot);
15294                        let goal = SelectionGoal::HorizontalPosition(
15295                            display_snapshot
15296                                .x_for_display_point(display_point, text_layout_details)
15297                                .into(),
15298                        );
15299                        (display_point, goal)
15300                    })
15301                });
15302            }
15303        });
15304    }
15305
15306    pub fn select_enclosing_symbol(
15307        &mut self,
15308        _: &SelectEnclosingSymbol,
15309        window: &mut Window,
15310        cx: &mut Context<Self>,
15311    ) {
15312        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15313
15314        let buffer = self.buffer.read(cx).snapshot(cx);
15315        let old_selections = self
15316            .selections
15317            .all::<usize>(&self.display_snapshot(cx))
15318            .into_boxed_slice();
15319
15320        fn update_selection(
15321            selection: &Selection<usize>,
15322            buffer_snap: &MultiBufferSnapshot,
15323        ) -> Option<Selection<usize>> {
15324            let cursor = selection.head();
15325            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
15326            for symbol in symbols.iter().rev() {
15327                let start = symbol.range.start.to_offset(buffer_snap);
15328                let end = symbol.range.end.to_offset(buffer_snap);
15329                let new_range = start..end;
15330                if start < selection.start || end > selection.end {
15331                    return Some(Selection {
15332                        id: selection.id,
15333                        start: new_range.start,
15334                        end: new_range.end,
15335                        goal: SelectionGoal::None,
15336                        reversed: selection.reversed,
15337                    });
15338                }
15339            }
15340            None
15341        }
15342
15343        let mut selected_larger_symbol = false;
15344        let new_selections = old_selections
15345            .iter()
15346            .map(|selection| match update_selection(selection, &buffer) {
15347                Some(new_selection) => {
15348                    if new_selection.range() != selection.range() {
15349                        selected_larger_symbol = true;
15350                    }
15351                    new_selection
15352                }
15353                None => selection.clone(),
15354            })
15355            .collect::<Vec<_>>();
15356
15357        if selected_larger_symbol {
15358            self.change_selections(Default::default(), window, cx, |s| {
15359                s.select(new_selections);
15360            });
15361        }
15362    }
15363
15364    pub fn select_larger_syntax_node(
15365        &mut self,
15366        _: &SelectLargerSyntaxNode,
15367        window: &mut Window,
15368        cx: &mut Context<Self>,
15369    ) {
15370        let Some(visible_row_count) = self.visible_row_count() else {
15371            return;
15372        };
15373        let old_selections: Box<[_]> = self
15374            .selections
15375            .all::<usize>(&self.display_snapshot(cx))
15376            .into();
15377        if old_selections.is_empty() {
15378            return;
15379        }
15380
15381        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15382
15383        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15384        let buffer = self.buffer.read(cx).snapshot(cx);
15385
15386        let mut selected_larger_node = false;
15387        let mut new_selections = old_selections
15388            .iter()
15389            .map(|selection| {
15390                let old_range = selection.start..selection.end;
15391
15392                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
15393                    // manually select word at selection
15394                    if ["string_content", "inline"].contains(&node.kind()) {
15395                        let (word_range, _) = buffer.surrounding_word(old_range.start, None);
15396                        // ignore if word is already selected
15397                        if !word_range.is_empty() && old_range != word_range {
15398                            let (last_word_range, _) = buffer.surrounding_word(old_range.end, None);
15399                            // only select word if start and end point belongs to same word
15400                            if word_range == last_word_range {
15401                                selected_larger_node = true;
15402                                return Selection {
15403                                    id: selection.id,
15404                                    start: word_range.start,
15405                                    end: word_range.end,
15406                                    goal: SelectionGoal::None,
15407                                    reversed: selection.reversed,
15408                                };
15409                            }
15410                        }
15411                    }
15412                }
15413
15414                let mut new_range = old_range.clone();
15415                while let Some((node, range)) = buffer.syntax_ancestor(new_range.clone()) {
15416                    new_range = range;
15417                    if !node.is_named() {
15418                        continue;
15419                    }
15420                    if !display_map.intersects_fold(new_range.start)
15421                        && !display_map.intersects_fold(new_range.end)
15422                    {
15423                        break;
15424                    }
15425                }
15426
15427                selected_larger_node |= new_range != old_range;
15428                Selection {
15429                    id: selection.id,
15430                    start: new_range.start,
15431                    end: new_range.end,
15432                    goal: SelectionGoal::None,
15433                    reversed: selection.reversed,
15434                }
15435            })
15436            .collect::<Vec<_>>();
15437
15438        if !selected_larger_node {
15439            return; // don't put this call in the history
15440        }
15441
15442        // scroll based on transformation done to the last selection created by the user
15443        let (last_old, last_new) = old_selections
15444            .last()
15445            .zip(new_selections.last().cloned())
15446            .expect("old_selections isn't empty");
15447
15448        // revert selection
15449        let is_selection_reversed = {
15450            let should_newest_selection_be_reversed = last_old.start != last_new.start;
15451            new_selections.last_mut().expect("checked above").reversed =
15452                should_newest_selection_be_reversed;
15453            should_newest_selection_be_reversed
15454        };
15455
15456        if selected_larger_node {
15457            self.select_syntax_node_history.disable_clearing = true;
15458            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15459                s.select(new_selections.clone());
15460            });
15461            self.select_syntax_node_history.disable_clearing = false;
15462        }
15463
15464        let start_row = last_new.start.to_display_point(&display_map).row().0;
15465        let end_row = last_new.end.to_display_point(&display_map).row().0;
15466        let selection_height = end_row - start_row + 1;
15467        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
15468
15469        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
15470        let scroll_behavior = if fits_on_the_screen {
15471            self.request_autoscroll(Autoscroll::fit(), cx);
15472            SelectSyntaxNodeScrollBehavior::FitSelection
15473        } else if is_selection_reversed {
15474            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15475            SelectSyntaxNodeScrollBehavior::CursorTop
15476        } else {
15477            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15478            SelectSyntaxNodeScrollBehavior::CursorBottom
15479        };
15480
15481        self.select_syntax_node_history.push((
15482            old_selections,
15483            scroll_behavior,
15484            is_selection_reversed,
15485        ));
15486    }
15487
15488    pub fn select_smaller_syntax_node(
15489        &mut self,
15490        _: &SelectSmallerSyntaxNode,
15491        window: &mut Window,
15492        cx: &mut Context<Self>,
15493    ) {
15494        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15495
15496        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
15497            self.select_syntax_node_history.pop()
15498        {
15499            if let Some(selection) = selections.last_mut() {
15500                selection.reversed = is_selection_reversed;
15501            }
15502
15503            self.select_syntax_node_history.disable_clearing = true;
15504            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15505                s.select(selections.to_vec());
15506            });
15507            self.select_syntax_node_history.disable_clearing = false;
15508
15509            match scroll_behavior {
15510                SelectSyntaxNodeScrollBehavior::CursorTop => {
15511                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15512                }
15513                SelectSyntaxNodeScrollBehavior::FitSelection => {
15514                    self.request_autoscroll(Autoscroll::fit(), cx);
15515                }
15516                SelectSyntaxNodeScrollBehavior::CursorBottom => {
15517                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15518                }
15519            }
15520        }
15521    }
15522
15523    pub fn unwrap_syntax_node(
15524        &mut self,
15525        _: &UnwrapSyntaxNode,
15526        window: &mut Window,
15527        cx: &mut Context<Self>,
15528    ) {
15529        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15530
15531        let buffer = self.buffer.read(cx).snapshot(cx);
15532        let selections = self
15533            .selections
15534            .all::<usize>(&self.display_snapshot(cx))
15535            .into_iter()
15536            // subtracting the offset requires sorting
15537            .sorted_by_key(|i| i.start);
15538
15539        let full_edits = selections
15540            .into_iter()
15541            .filter_map(|selection| {
15542                let child = if selection.is_empty()
15543                    && let Some((_, ancestor_range)) =
15544                        buffer.syntax_ancestor(selection.start..selection.end)
15545                {
15546                    ancestor_range
15547                } else {
15548                    selection.range()
15549                };
15550
15551                let mut parent = child.clone();
15552                while let Some((_, ancestor_range)) = buffer.syntax_ancestor(parent.clone()) {
15553                    parent = ancestor_range;
15554                    if parent.start < child.start || parent.end > child.end {
15555                        break;
15556                    }
15557                }
15558
15559                if parent == child {
15560                    return None;
15561                }
15562                let text = buffer.text_for_range(child).collect::<String>();
15563                Some((selection.id, parent, text))
15564            })
15565            .collect::<Vec<_>>();
15566        if full_edits.is_empty() {
15567            return;
15568        }
15569
15570        self.transact(window, cx, |this, window, cx| {
15571            this.buffer.update(cx, |buffer, cx| {
15572                buffer.edit(
15573                    full_edits
15574                        .iter()
15575                        .map(|(_, p, t)| (p.clone(), t.clone()))
15576                        .collect::<Vec<_>>(),
15577                    None,
15578                    cx,
15579                );
15580            });
15581            this.change_selections(Default::default(), window, cx, |s| {
15582                let mut offset = 0;
15583                let mut selections = vec![];
15584                for (id, parent, text) in full_edits {
15585                    let start = parent.start - offset;
15586                    offset += parent.len() - text.len();
15587                    selections.push(Selection {
15588                        id,
15589                        start,
15590                        end: start + text.len(),
15591                        reversed: false,
15592                        goal: Default::default(),
15593                    });
15594                }
15595                s.select(selections);
15596            });
15597        });
15598    }
15599
15600    pub fn select_next_syntax_node(
15601        &mut self,
15602        _: &SelectNextSyntaxNode,
15603        window: &mut Window,
15604        cx: &mut Context<Self>,
15605    ) {
15606        let old_selections: Box<[_]> = self
15607            .selections
15608            .all::<usize>(&self.display_snapshot(cx))
15609            .into();
15610        if old_selections.is_empty() {
15611            return;
15612        }
15613
15614        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15615
15616        let buffer = self.buffer.read(cx).snapshot(cx);
15617        let mut selected_sibling = false;
15618
15619        let new_selections = old_selections
15620            .iter()
15621            .map(|selection| {
15622                let old_range = selection.start..selection.end;
15623
15624                if let Some(node) = buffer.syntax_next_sibling(old_range) {
15625                    let new_range = node.byte_range();
15626                    selected_sibling = true;
15627                    Selection {
15628                        id: selection.id,
15629                        start: new_range.start,
15630                        end: new_range.end,
15631                        goal: SelectionGoal::None,
15632                        reversed: selection.reversed,
15633                    }
15634                } else {
15635                    selection.clone()
15636                }
15637            })
15638            .collect::<Vec<_>>();
15639
15640        if selected_sibling {
15641            self.change_selections(
15642                SelectionEffects::scroll(Autoscroll::fit()),
15643                window,
15644                cx,
15645                |s| {
15646                    s.select(new_selections);
15647                },
15648            );
15649        }
15650    }
15651
15652    pub fn select_prev_syntax_node(
15653        &mut self,
15654        _: &SelectPreviousSyntaxNode,
15655        window: &mut Window,
15656        cx: &mut Context<Self>,
15657    ) {
15658        let old_selections: Box<[_]> = self
15659            .selections
15660            .all::<usize>(&self.display_snapshot(cx))
15661            .into();
15662        if old_selections.is_empty() {
15663            return;
15664        }
15665
15666        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15667
15668        let buffer = self.buffer.read(cx).snapshot(cx);
15669        let mut selected_sibling = false;
15670
15671        let new_selections = old_selections
15672            .iter()
15673            .map(|selection| {
15674                let old_range = selection.start..selection.end;
15675
15676                if let Some(node) = buffer.syntax_prev_sibling(old_range) {
15677                    let new_range = node.byte_range();
15678                    selected_sibling = true;
15679                    Selection {
15680                        id: selection.id,
15681                        start: new_range.start,
15682                        end: new_range.end,
15683                        goal: SelectionGoal::None,
15684                        reversed: selection.reversed,
15685                    }
15686                } else {
15687                    selection.clone()
15688                }
15689            })
15690            .collect::<Vec<_>>();
15691
15692        if selected_sibling {
15693            self.change_selections(
15694                SelectionEffects::scroll(Autoscroll::fit()),
15695                window,
15696                cx,
15697                |s| {
15698                    s.select(new_selections);
15699                },
15700            );
15701        }
15702    }
15703
15704    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
15705        if !EditorSettings::get_global(cx).gutter.runnables {
15706            self.clear_tasks();
15707            return Task::ready(());
15708        }
15709        let project = self.project().map(Entity::downgrade);
15710        let task_sources = self.lsp_task_sources(cx);
15711        let multi_buffer = self.buffer.downgrade();
15712        cx.spawn_in(window, async move |editor, cx| {
15713            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
15714            let Some(project) = project.and_then(|p| p.upgrade()) else {
15715                return;
15716            };
15717            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
15718                this.display_map.update(cx, |map, cx| map.snapshot(cx))
15719            }) else {
15720                return;
15721            };
15722
15723            let hide_runnables = project
15724                .update(cx, |project, _| project.is_via_collab())
15725                .unwrap_or(true);
15726            if hide_runnables {
15727                return;
15728            }
15729            let new_rows =
15730                cx.background_spawn({
15731                    let snapshot = display_snapshot.clone();
15732                    async move {
15733                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
15734                    }
15735                })
15736                    .await;
15737            let Ok(lsp_tasks) =
15738                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
15739            else {
15740                return;
15741            };
15742            let lsp_tasks = lsp_tasks.await;
15743
15744            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
15745                lsp_tasks
15746                    .into_iter()
15747                    .flat_map(|(kind, tasks)| {
15748                        tasks.into_iter().filter_map(move |(location, task)| {
15749                            Some((kind.clone(), location?, task))
15750                        })
15751                    })
15752                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
15753                        let buffer = location.target.buffer;
15754                        let buffer_snapshot = buffer.read(cx).snapshot();
15755                        let offset = display_snapshot.buffer_snapshot().excerpts().find_map(
15756                            |(excerpt_id, snapshot, _)| {
15757                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
15758                                    display_snapshot
15759                                        .buffer_snapshot()
15760                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
15761                                } else {
15762                                    None
15763                                }
15764                            },
15765                        );
15766                        if let Some(offset) = offset {
15767                            let task_buffer_range =
15768                                location.target.range.to_point(&buffer_snapshot);
15769                            let context_buffer_range =
15770                                task_buffer_range.to_offset(&buffer_snapshot);
15771                            let context_range = BufferOffset(context_buffer_range.start)
15772                                ..BufferOffset(context_buffer_range.end);
15773
15774                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
15775                                .or_insert_with(|| RunnableTasks {
15776                                    templates: Vec::new(),
15777                                    offset,
15778                                    column: task_buffer_range.start.column,
15779                                    extra_variables: HashMap::default(),
15780                                    context_range,
15781                                })
15782                                .templates
15783                                .push((kind, task.original_task().clone()));
15784                        }
15785
15786                        acc
15787                    })
15788            }) else {
15789                return;
15790            };
15791
15792            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
15793                buffer.language_settings(cx).tasks.prefer_lsp
15794            }) else {
15795                return;
15796            };
15797
15798            let rows = Self::runnable_rows(
15799                project,
15800                display_snapshot,
15801                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
15802                new_rows,
15803                cx.clone(),
15804            )
15805            .await;
15806            editor
15807                .update(cx, |editor, _| {
15808                    editor.clear_tasks();
15809                    for (key, mut value) in rows {
15810                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
15811                            value.templates.extend(lsp_tasks.templates);
15812                        }
15813
15814                        editor.insert_tasks(key, value);
15815                    }
15816                    for (key, value) in lsp_tasks_by_rows {
15817                        editor.insert_tasks(key, value);
15818                    }
15819                })
15820                .ok();
15821        })
15822    }
15823    fn fetch_runnable_ranges(
15824        snapshot: &DisplaySnapshot,
15825        range: Range<Anchor>,
15826    ) -> Vec<language::RunnableRange> {
15827        snapshot.buffer_snapshot().runnable_ranges(range).collect()
15828    }
15829
15830    fn runnable_rows(
15831        project: Entity<Project>,
15832        snapshot: DisplaySnapshot,
15833        prefer_lsp: bool,
15834        runnable_ranges: Vec<RunnableRange>,
15835        cx: AsyncWindowContext,
15836    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
15837        cx.spawn(async move |cx| {
15838            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
15839            for mut runnable in runnable_ranges {
15840                let Some(tasks) = cx
15841                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
15842                    .ok()
15843                else {
15844                    continue;
15845                };
15846                let mut tasks = tasks.await;
15847
15848                if prefer_lsp {
15849                    tasks.retain(|(task_kind, _)| {
15850                        !matches!(task_kind, TaskSourceKind::Language { .. })
15851                    });
15852                }
15853                if tasks.is_empty() {
15854                    continue;
15855                }
15856
15857                let point = runnable
15858                    .run_range
15859                    .start
15860                    .to_point(&snapshot.buffer_snapshot());
15861                let Some(row) = snapshot
15862                    .buffer_snapshot()
15863                    .buffer_line_for_row(MultiBufferRow(point.row))
15864                    .map(|(_, range)| range.start.row)
15865                else {
15866                    continue;
15867                };
15868
15869                let context_range =
15870                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
15871                runnable_rows.push((
15872                    (runnable.buffer_id, row),
15873                    RunnableTasks {
15874                        templates: tasks,
15875                        offset: snapshot
15876                            .buffer_snapshot()
15877                            .anchor_before(runnable.run_range.start),
15878                        context_range,
15879                        column: point.column,
15880                        extra_variables: runnable.extra_captures,
15881                    },
15882                ));
15883            }
15884            runnable_rows
15885        })
15886    }
15887
15888    fn templates_with_tags(
15889        project: &Entity<Project>,
15890        runnable: &mut Runnable,
15891        cx: &mut App,
15892    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
15893        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
15894            let (worktree_id, file) = project
15895                .buffer_for_id(runnable.buffer, cx)
15896                .and_then(|buffer| buffer.read(cx).file())
15897                .map(|file| (file.worktree_id(cx), file.clone()))
15898                .unzip();
15899
15900            (
15901                project.task_store().read(cx).task_inventory().cloned(),
15902                worktree_id,
15903                file,
15904            )
15905        });
15906
15907        let tags = mem::take(&mut runnable.tags);
15908        let language = runnable.language.clone();
15909        cx.spawn(async move |cx| {
15910            let mut templates_with_tags = Vec::new();
15911            if let Some(inventory) = inventory {
15912                for RunnableTag(tag) in tags {
15913                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
15914                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
15915                    }) else {
15916                        return templates_with_tags;
15917                    };
15918                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
15919                        move |(_, template)| {
15920                            template.tags.iter().any(|source_tag| source_tag == &tag)
15921                        },
15922                    ));
15923                }
15924            }
15925            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
15926
15927            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
15928                // Strongest source wins; if we have worktree tag binding, prefer that to
15929                // global and language bindings;
15930                // if we have a global binding, prefer that to language binding.
15931                let first_mismatch = templates_with_tags
15932                    .iter()
15933                    .position(|(tag_source, _)| tag_source != leading_tag_source);
15934                if let Some(index) = first_mismatch {
15935                    templates_with_tags.truncate(index);
15936                }
15937            }
15938
15939            templates_with_tags
15940        })
15941    }
15942
15943    pub fn move_to_enclosing_bracket(
15944        &mut self,
15945        _: &MoveToEnclosingBracket,
15946        window: &mut Window,
15947        cx: &mut Context<Self>,
15948    ) {
15949        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15950        self.change_selections(Default::default(), window, cx, |s| {
15951            s.move_offsets_with(|snapshot, selection| {
15952                let Some(enclosing_bracket_ranges) =
15953                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
15954                else {
15955                    return;
15956                };
15957
15958                let mut best_length = usize::MAX;
15959                let mut best_inside = false;
15960                let mut best_in_bracket_range = false;
15961                let mut best_destination = None;
15962                for (open, close) in enclosing_bracket_ranges {
15963                    let close = close.to_inclusive();
15964                    let length = close.end() - open.start;
15965                    let inside = selection.start >= open.end && selection.end <= *close.start();
15966                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
15967                        || close.contains(&selection.head());
15968
15969                    // If best is next to a bracket and current isn't, skip
15970                    if !in_bracket_range && best_in_bracket_range {
15971                        continue;
15972                    }
15973
15974                    // Prefer smaller lengths unless best is inside and current isn't
15975                    if length > best_length && (best_inside || !inside) {
15976                        continue;
15977                    }
15978
15979                    best_length = length;
15980                    best_inside = inside;
15981                    best_in_bracket_range = in_bracket_range;
15982                    best_destination = Some(
15983                        if close.contains(&selection.start) && close.contains(&selection.end) {
15984                            if inside { open.end } else { open.start }
15985                        } else if inside {
15986                            *close.start()
15987                        } else {
15988                            *close.end()
15989                        },
15990                    );
15991                }
15992
15993                if let Some(destination) = best_destination {
15994                    selection.collapse_to(destination, SelectionGoal::None);
15995                }
15996            })
15997        });
15998    }
15999
16000    pub fn undo_selection(
16001        &mut self,
16002        _: &UndoSelection,
16003        window: &mut Window,
16004        cx: &mut Context<Self>,
16005    ) {
16006        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16007        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
16008            self.selection_history.mode = SelectionHistoryMode::Undoing;
16009            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
16010                this.end_selection(window, cx);
16011                this.change_selections(
16012                    SelectionEffects::scroll(Autoscroll::newest()),
16013                    window,
16014                    cx,
16015                    |s| s.select_anchors(entry.selections.to_vec()),
16016                );
16017            });
16018            self.selection_history.mode = SelectionHistoryMode::Normal;
16019
16020            self.select_next_state = entry.select_next_state;
16021            self.select_prev_state = entry.select_prev_state;
16022            self.add_selections_state = entry.add_selections_state;
16023        }
16024    }
16025
16026    pub fn redo_selection(
16027        &mut self,
16028        _: &RedoSelection,
16029        window: &mut Window,
16030        cx: &mut Context<Self>,
16031    ) {
16032        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16033        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
16034            self.selection_history.mode = SelectionHistoryMode::Redoing;
16035            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
16036                this.end_selection(window, cx);
16037                this.change_selections(
16038                    SelectionEffects::scroll(Autoscroll::newest()),
16039                    window,
16040                    cx,
16041                    |s| s.select_anchors(entry.selections.to_vec()),
16042                );
16043            });
16044            self.selection_history.mode = SelectionHistoryMode::Normal;
16045
16046            self.select_next_state = entry.select_next_state;
16047            self.select_prev_state = entry.select_prev_state;
16048            self.add_selections_state = entry.add_selections_state;
16049        }
16050    }
16051
16052    pub fn expand_excerpts(
16053        &mut self,
16054        action: &ExpandExcerpts,
16055        _: &mut Window,
16056        cx: &mut Context<Self>,
16057    ) {
16058        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
16059    }
16060
16061    pub fn expand_excerpts_down(
16062        &mut self,
16063        action: &ExpandExcerptsDown,
16064        _: &mut Window,
16065        cx: &mut Context<Self>,
16066    ) {
16067        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
16068    }
16069
16070    pub fn expand_excerpts_up(
16071        &mut self,
16072        action: &ExpandExcerptsUp,
16073        _: &mut Window,
16074        cx: &mut Context<Self>,
16075    ) {
16076        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
16077    }
16078
16079    pub fn expand_excerpts_for_direction(
16080        &mut self,
16081        lines: u32,
16082        direction: ExpandExcerptDirection,
16083
16084        cx: &mut Context<Self>,
16085    ) {
16086        let selections = self.selections.disjoint_anchors_arc();
16087
16088        let lines = if lines == 0 {
16089            EditorSettings::get_global(cx).expand_excerpt_lines
16090        } else {
16091            lines
16092        };
16093
16094        self.buffer.update(cx, |buffer, cx| {
16095            let snapshot = buffer.snapshot(cx);
16096            let mut excerpt_ids = selections
16097                .iter()
16098                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
16099                .collect::<Vec<_>>();
16100            excerpt_ids.sort();
16101            excerpt_ids.dedup();
16102            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
16103        })
16104    }
16105
16106    pub fn expand_excerpt(
16107        &mut self,
16108        excerpt: ExcerptId,
16109        direction: ExpandExcerptDirection,
16110        window: &mut Window,
16111        cx: &mut Context<Self>,
16112    ) {
16113        let current_scroll_position = self.scroll_position(cx);
16114        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
16115        let mut scroll = None;
16116
16117        if direction == ExpandExcerptDirection::Down {
16118            let multi_buffer = self.buffer.read(cx);
16119            let snapshot = multi_buffer.snapshot(cx);
16120            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt)
16121                && let Some(buffer) = multi_buffer.buffer(buffer_id)
16122                && let Some(excerpt_range) = snapshot.context_range_for_excerpt(excerpt)
16123            {
16124                let buffer_snapshot = buffer.read(cx).snapshot();
16125                let excerpt_end_row = Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
16126                let last_row = buffer_snapshot.max_point().row;
16127                let lines_below = last_row.saturating_sub(excerpt_end_row);
16128                if lines_below >= lines_to_expand {
16129                    scroll = Some(
16130                        current_scroll_position
16131                            + gpui::Point::new(0.0, lines_to_expand as ScrollOffset),
16132                    );
16133                }
16134            }
16135        }
16136        if direction == ExpandExcerptDirection::Up
16137            && self
16138                .buffer
16139                .read(cx)
16140                .snapshot(cx)
16141                .excerpt_before(excerpt)
16142                .is_none()
16143        {
16144            scroll = Some(current_scroll_position);
16145        }
16146
16147        self.buffer.update(cx, |buffer, cx| {
16148            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
16149        });
16150
16151        if let Some(new_scroll_position) = scroll {
16152            self.set_scroll_position(new_scroll_position, window, cx);
16153        }
16154    }
16155
16156    pub fn go_to_singleton_buffer_point(
16157        &mut self,
16158        point: Point,
16159        window: &mut Window,
16160        cx: &mut Context<Self>,
16161    ) {
16162        self.go_to_singleton_buffer_range(point..point, window, cx);
16163    }
16164
16165    pub fn go_to_singleton_buffer_range(
16166        &mut self,
16167        range: Range<Point>,
16168        window: &mut Window,
16169        cx: &mut Context<Self>,
16170    ) {
16171        let multibuffer = self.buffer().read(cx);
16172        let Some(buffer) = multibuffer.as_singleton() else {
16173            return;
16174        };
16175        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
16176            return;
16177        };
16178        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
16179            return;
16180        };
16181        self.change_selections(
16182            SelectionEffects::default().nav_history(true),
16183            window,
16184            cx,
16185            |s| s.select_anchor_ranges([start..end]),
16186        );
16187    }
16188
16189    pub fn go_to_diagnostic(
16190        &mut self,
16191        action: &GoToDiagnostic,
16192        window: &mut Window,
16193        cx: &mut Context<Self>,
16194    ) {
16195        if !self.diagnostics_enabled() {
16196            return;
16197        }
16198        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16199        self.go_to_diagnostic_impl(Direction::Next, action.severity, window, cx)
16200    }
16201
16202    pub fn go_to_prev_diagnostic(
16203        &mut self,
16204        action: &GoToPreviousDiagnostic,
16205        window: &mut Window,
16206        cx: &mut Context<Self>,
16207    ) {
16208        if !self.diagnostics_enabled() {
16209            return;
16210        }
16211        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16212        self.go_to_diagnostic_impl(Direction::Prev, action.severity, window, cx)
16213    }
16214
16215    pub fn go_to_diagnostic_impl(
16216        &mut self,
16217        direction: Direction,
16218        severity: GoToDiagnosticSeverityFilter,
16219        window: &mut Window,
16220        cx: &mut Context<Self>,
16221    ) {
16222        let buffer = self.buffer.read(cx).snapshot(cx);
16223        let selection = self.selections.newest::<usize>(&self.display_snapshot(cx));
16224
16225        let mut active_group_id = None;
16226        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics
16227            && active_group.active_range.start.to_offset(&buffer) == selection.start
16228        {
16229            active_group_id = Some(active_group.group_id);
16230        }
16231
16232        fn filtered<'a>(
16233            severity: GoToDiagnosticSeverityFilter,
16234            diagnostics: impl Iterator<Item = DiagnosticEntryRef<'a, usize>>,
16235        ) -> impl Iterator<Item = DiagnosticEntryRef<'a, usize>> {
16236            diagnostics
16237                .filter(move |entry| severity.matches(entry.diagnostic.severity))
16238                .filter(|entry| entry.range.start != entry.range.end)
16239                .filter(|entry| !entry.diagnostic.is_unnecessary)
16240        }
16241
16242        let before = filtered(
16243            severity,
16244            buffer
16245                .diagnostics_in_range(0..selection.start)
16246                .filter(|entry| entry.range.start <= selection.start),
16247        );
16248        let after = filtered(
16249            severity,
16250            buffer
16251                .diagnostics_in_range(selection.start..buffer.len())
16252                .filter(|entry| entry.range.start >= selection.start),
16253        );
16254
16255        let mut found: Option<DiagnosticEntryRef<usize>> = None;
16256        if direction == Direction::Prev {
16257            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
16258            {
16259                for diagnostic in prev_diagnostics.into_iter().rev() {
16260                    if diagnostic.range.start != selection.start
16261                        || active_group_id
16262                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
16263                    {
16264                        found = Some(diagnostic);
16265                        break 'outer;
16266                    }
16267                }
16268            }
16269        } else {
16270            for diagnostic in after.chain(before) {
16271                if diagnostic.range.start != selection.start
16272                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
16273                {
16274                    found = Some(diagnostic);
16275                    break;
16276                }
16277            }
16278        }
16279        let Some(next_diagnostic) = found else {
16280            return;
16281        };
16282
16283        let next_diagnostic_start = buffer.anchor_after(next_diagnostic.range.start);
16284        let Some(buffer_id) = buffer.buffer_id_for_anchor(next_diagnostic_start) else {
16285            return;
16286        };
16287        let snapshot = self.snapshot(window, cx);
16288        if snapshot.intersects_fold(next_diagnostic.range.start) {
16289            self.unfold_ranges(
16290                std::slice::from_ref(&next_diagnostic.range),
16291                true,
16292                false,
16293                cx,
16294            );
16295        }
16296        self.change_selections(Default::default(), window, cx, |s| {
16297            s.select_ranges(vec![
16298                next_diagnostic.range.start..next_diagnostic.range.start,
16299            ])
16300        });
16301        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
16302        self.refresh_edit_prediction(false, true, window, cx);
16303    }
16304
16305    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
16306        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16307        let snapshot = self.snapshot(window, cx);
16308        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
16309        self.go_to_hunk_before_or_after_position(
16310            &snapshot,
16311            selection.head(),
16312            Direction::Next,
16313            window,
16314            cx,
16315        );
16316    }
16317
16318    pub fn go_to_hunk_before_or_after_position(
16319        &mut self,
16320        snapshot: &EditorSnapshot,
16321        position: Point,
16322        direction: Direction,
16323        window: &mut Window,
16324        cx: &mut Context<Editor>,
16325    ) {
16326        let row = if direction == Direction::Next {
16327            self.hunk_after_position(snapshot, position)
16328                .map(|hunk| hunk.row_range.start)
16329        } else {
16330            self.hunk_before_position(snapshot, position)
16331        };
16332
16333        if let Some(row) = row {
16334            let destination = Point::new(row.0, 0);
16335            let autoscroll = Autoscroll::center();
16336
16337            self.unfold_ranges(&[destination..destination], false, false, cx);
16338            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16339                s.select_ranges([destination..destination]);
16340            });
16341        }
16342    }
16343
16344    fn hunk_after_position(
16345        &mut self,
16346        snapshot: &EditorSnapshot,
16347        position: Point,
16348    ) -> Option<MultiBufferDiffHunk> {
16349        snapshot
16350            .buffer_snapshot()
16351            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
16352            .find(|hunk| hunk.row_range.start.0 > position.row)
16353            .or_else(|| {
16354                snapshot
16355                    .buffer_snapshot()
16356                    .diff_hunks_in_range(Point::zero()..position)
16357                    .find(|hunk| hunk.row_range.end.0 < position.row)
16358            })
16359    }
16360
16361    fn go_to_prev_hunk(
16362        &mut self,
16363        _: &GoToPreviousHunk,
16364        window: &mut Window,
16365        cx: &mut Context<Self>,
16366    ) {
16367        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16368        let snapshot = self.snapshot(window, cx);
16369        let selection = self.selections.newest::<Point>(&snapshot.display_snapshot);
16370        self.go_to_hunk_before_or_after_position(
16371            &snapshot,
16372            selection.head(),
16373            Direction::Prev,
16374            window,
16375            cx,
16376        );
16377    }
16378
16379    fn hunk_before_position(
16380        &mut self,
16381        snapshot: &EditorSnapshot,
16382        position: Point,
16383    ) -> Option<MultiBufferRow> {
16384        snapshot
16385            .buffer_snapshot()
16386            .diff_hunk_before(position)
16387            .or_else(|| snapshot.buffer_snapshot().diff_hunk_before(Point::MAX))
16388    }
16389
16390    fn go_to_next_change(
16391        &mut self,
16392        _: &GoToNextChange,
16393        window: &mut Window,
16394        cx: &mut Context<Self>,
16395    ) {
16396        if let Some(selections) = self
16397            .change_list
16398            .next_change(1, Direction::Next)
16399            .map(|s| s.to_vec())
16400        {
16401            self.change_selections(Default::default(), window, cx, |s| {
16402                let map = s.display_snapshot();
16403                s.select_display_ranges(selections.iter().map(|a| {
16404                    let point = a.to_display_point(&map);
16405                    point..point
16406                }))
16407            })
16408        }
16409    }
16410
16411    fn go_to_previous_change(
16412        &mut self,
16413        _: &GoToPreviousChange,
16414        window: &mut Window,
16415        cx: &mut Context<Self>,
16416    ) {
16417        if let Some(selections) = self
16418            .change_list
16419            .next_change(1, Direction::Prev)
16420            .map(|s| s.to_vec())
16421        {
16422            self.change_selections(Default::default(), window, cx, |s| {
16423                let map = s.display_snapshot();
16424                s.select_display_ranges(selections.iter().map(|a| {
16425                    let point = a.to_display_point(&map);
16426                    point..point
16427                }))
16428            })
16429        }
16430    }
16431
16432    pub fn go_to_next_document_highlight(
16433        &mut self,
16434        _: &GoToNextDocumentHighlight,
16435        window: &mut Window,
16436        cx: &mut Context<Self>,
16437    ) {
16438        self.go_to_document_highlight_before_or_after_position(Direction::Next, window, cx);
16439    }
16440
16441    pub fn go_to_prev_document_highlight(
16442        &mut self,
16443        _: &GoToPreviousDocumentHighlight,
16444        window: &mut Window,
16445        cx: &mut Context<Self>,
16446    ) {
16447        self.go_to_document_highlight_before_or_after_position(Direction::Prev, window, cx);
16448    }
16449
16450    pub fn go_to_document_highlight_before_or_after_position(
16451        &mut self,
16452        direction: Direction,
16453        window: &mut Window,
16454        cx: &mut Context<Editor>,
16455    ) {
16456        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16457        let snapshot = self.snapshot(window, cx);
16458        let buffer = &snapshot.buffer_snapshot();
16459        let position = self
16460            .selections
16461            .newest::<Point>(&snapshot.display_snapshot)
16462            .head();
16463        let anchor_position = buffer.anchor_after(position);
16464
16465        // Get all document highlights (both read and write)
16466        let mut all_highlights = Vec::new();
16467
16468        if let Some((_, read_highlights)) = self
16469            .background_highlights
16470            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
16471        {
16472            all_highlights.extend(read_highlights.iter());
16473        }
16474
16475        if let Some((_, write_highlights)) = self
16476            .background_highlights
16477            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
16478        {
16479            all_highlights.extend(write_highlights.iter());
16480        }
16481
16482        if all_highlights.is_empty() {
16483            return;
16484        }
16485
16486        // Sort highlights by position
16487        all_highlights.sort_by(|a, b| a.start.cmp(&b.start, buffer));
16488
16489        let target_highlight = match direction {
16490            Direction::Next => {
16491                // Find the first highlight after the current position
16492                all_highlights
16493                    .iter()
16494                    .find(|highlight| highlight.start.cmp(&anchor_position, buffer).is_gt())
16495            }
16496            Direction::Prev => {
16497                // Find the last highlight before the current position
16498                all_highlights
16499                    .iter()
16500                    .rev()
16501                    .find(|highlight| highlight.end.cmp(&anchor_position, buffer).is_lt())
16502            }
16503        };
16504
16505        if let Some(highlight) = target_highlight {
16506            let destination = highlight.start.to_point(buffer);
16507            let autoscroll = Autoscroll::center();
16508
16509            self.unfold_ranges(&[destination..destination], false, false, cx);
16510            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16511                s.select_ranges([destination..destination]);
16512            });
16513        }
16514    }
16515
16516    fn go_to_line<T: 'static>(
16517        &mut self,
16518        position: Anchor,
16519        highlight_color: Option<Hsla>,
16520        window: &mut Window,
16521        cx: &mut Context<Self>,
16522    ) {
16523        let snapshot = self.snapshot(window, cx).display_snapshot;
16524        let position = position.to_point(&snapshot.buffer_snapshot());
16525        let start = snapshot
16526            .buffer_snapshot()
16527            .clip_point(Point::new(position.row, 0), Bias::Left);
16528        let end = start + Point::new(1, 0);
16529        let start = snapshot.buffer_snapshot().anchor_before(start);
16530        let end = snapshot.buffer_snapshot().anchor_before(end);
16531
16532        self.highlight_rows::<T>(
16533            start..end,
16534            highlight_color
16535                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
16536            Default::default(),
16537            cx,
16538        );
16539
16540        if self.buffer.read(cx).is_singleton() {
16541            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
16542        }
16543    }
16544
16545    pub fn go_to_definition(
16546        &mut self,
16547        _: &GoToDefinition,
16548        window: &mut Window,
16549        cx: &mut Context<Self>,
16550    ) -> Task<Result<Navigated>> {
16551        let definition =
16552            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
16553        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
16554        cx.spawn_in(window, async move |editor, cx| {
16555            if definition.await? == Navigated::Yes {
16556                return Ok(Navigated::Yes);
16557            }
16558            match fallback_strategy {
16559                GoToDefinitionFallback::None => Ok(Navigated::No),
16560                GoToDefinitionFallback::FindAllReferences => {
16561                    match editor.update_in(cx, |editor, window, cx| {
16562                        editor.find_all_references(&FindAllReferences, window, cx)
16563                    })? {
16564                        Some(references) => references.await,
16565                        None => Ok(Navigated::No),
16566                    }
16567                }
16568            }
16569        })
16570    }
16571
16572    pub fn go_to_declaration(
16573        &mut self,
16574        _: &GoToDeclaration,
16575        window: &mut Window,
16576        cx: &mut Context<Self>,
16577    ) -> Task<Result<Navigated>> {
16578        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
16579    }
16580
16581    pub fn go_to_declaration_split(
16582        &mut self,
16583        _: &GoToDeclaration,
16584        window: &mut Window,
16585        cx: &mut Context<Self>,
16586    ) -> Task<Result<Navigated>> {
16587        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
16588    }
16589
16590    pub fn go_to_implementation(
16591        &mut self,
16592        _: &GoToImplementation,
16593        window: &mut Window,
16594        cx: &mut Context<Self>,
16595    ) -> Task<Result<Navigated>> {
16596        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
16597    }
16598
16599    pub fn go_to_implementation_split(
16600        &mut self,
16601        _: &GoToImplementationSplit,
16602        window: &mut Window,
16603        cx: &mut Context<Self>,
16604    ) -> Task<Result<Navigated>> {
16605        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
16606    }
16607
16608    pub fn go_to_type_definition(
16609        &mut self,
16610        _: &GoToTypeDefinition,
16611        window: &mut Window,
16612        cx: &mut Context<Self>,
16613    ) -> Task<Result<Navigated>> {
16614        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
16615    }
16616
16617    pub fn go_to_definition_split(
16618        &mut self,
16619        _: &GoToDefinitionSplit,
16620        window: &mut Window,
16621        cx: &mut Context<Self>,
16622    ) -> Task<Result<Navigated>> {
16623        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
16624    }
16625
16626    pub fn go_to_type_definition_split(
16627        &mut self,
16628        _: &GoToTypeDefinitionSplit,
16629        window: &mut Window,
16630        cx: &mut Context<Self>,
16631    ) -> Task<Result<Navigated>> {
16632        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
16633    }
16634
16635    fn go_to_definition_of_kind(
16636        &mut self,
16637        kind: GotoDefinitionKind,
16638        split: bool,
16639        window: &mut Window,
16640        cx: &mut Context<Self>,
16641    ) -> Task<Result<Navigated>> {
16642        let Some(provider) = self.semantics_provider.clone() else {
16643            return Task::ready(Ok(Navigated::No));
16644        };
16645        let head = self
16646            .selections
16647            .newest::<usize>(&self.display_snapshot(cx))
16648            .head();
16649        let buffer = self.buffer.read(cx);
16650        let Some((buffer, head)) = buffer.text_anchor_for_position(head, cx) else {
16651            return Task::ready(Ok(Navigated::No));
16652        };
16653        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
16654            return Task::ready(Ok(Navigated::No));
16655        };
16656
16657        cx.spawn_in(window, async move |editor, cx| {
16658            let Some(definitions) = definitions.await? else {
16659                return Ok(Navigated::No);
16660            };
16661            let navigated = editor
16662                .update_in(cx, |editor, window, cx| {
16663                    editor.navigate_to_hover_links(
16664                        Some(kind),
16665                        definitions
16666                            .into_iter()
16667                            .filter(|location| {
16668                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
16669                            })
16670                            .map(HoverLink::Text)
16671                            .collect::<Vec<_>>(),
16672                        split,
16673                        window,
16674                        cx,
16675                    )
16676                })?
16677                .await?;
16678            anyhow::Ok(navigated)
16679        })
16680    }
16681
16682    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
16683        let selection = self.selections.newest_anchor();
16684        let head = selection.head();
16685        let tail = selection.tail();
16686
16687        let Some((buffer, start_position)) =
16688            self.buffer.read(cx).text_anchor_for_position(head, cx)
16689        else {
16690            return;
16691        };
16692
16693        let end_position = if head != tail {
16694            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
16695                return;
16696            };
16697            Some(pos)
16698        } else {
16699            None
16700        };
16701
16702        let url_finder = cx.spawn_in(window, async move |_editor, cx| {
16703            let url = if let Some(end_pos) = end_position {
16704                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
16705            } else {
16706                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
16707            };
16708
16709            if let Some(url) = url {
16710                cx.update(|window, cx| {
16711                    if parse_zed_link(&url, cx).is_some() {
16712                        window.dispatch_action(Box::new(zed_actions::OpenZedUrl { url }), cx);
16713                    } else {
16714                        cx.open_url(&url);
16715                    }
16716                })?;
16717            }
16718
16719            anyhow::Ok(())
16720        });
16721
16722        url_finder.detach();
16723    }
16724
16725    pub fn open_selected_filename(
16726        &mut self,
16727        _: &OpenSelectedFilename,
16728        window: &mut Window,
16729        cx: &mut Context<Self>,
16730    ) {
16731        let Some(workspace) = self.workspace() else {
16732            return;
16733        };
16734
16735        let position = self.selections.newest_anchor().head();
16736
16737        let Some((buffer, buffer_position)) =
16738            self.buffer.read(cx).text_anchor_for_position(position, cx)
16739        else {
16740            return;
16741        };
16742
16743        let project = self.project.clone();
16744
16745        cx.spawn_in(window, async move |_, cx| {
16746            let result = find_file(&buffer, project, buffer_position, cx).await;
16747
16748            if let Some((_, path)) = result {
16749                workspace
16750                    .update_in(cx, |workspace, window, cx| {
16751                        workspace.open_resolved_path(path, window, cx)
16752                    })?
16753                    .await?;
16754            }
16755            anyhow::Ok(())
16756        })
16757        .detach();
16758    }
16759
16760    pub(crate) fn navigate_to_hover_links(
16761        &mut self,
16762        kind: Option<GotoDefinitionKind>,
16763        definitions: Vec<HoverLink>,
16764        split: bool,
16765        window: &mut Window,
16766        cx: &mut Context<Editor>,
16767    ) -> Task<Result<Navigated>> {
16768        // Separate out url and file links, we can only handle one of them at most or an arbitrary number of locations
16769        let mut first_url_or_file = None;
16770        let definitions: Vec<_> = definitions
16771            .into_iter()
16772            .filter_map(|def| match def {
16773                HoverLink::Text(link) => Some(Task::ready(anyhow::Ok(Some(link.target)))),
16774                HoverLink::InlayHint(lsp_location, server_id) => {
16775                    let computation =
16776                        self.compute_target_location(lsp_location, server_id, window, cx);
16777                    Some(cx.background_spawn(computation))
16778                }
16779                HoverLink::Url(url) => {
16780                    first_url_or_file = Some(Either::Left(url));
16781                    None
16782                }
16783                HoverLink::File(path) => {
16784                    first_url_or_file = Some(Either::Right(path));
16785                    None
16786                }
16787            })
16788            .collect();
16789
16790        let workspace = self.workspace();
16791
16792        cx.spawn_in(window, async move |editor, cx| {
16793            let locations: Vec<Location> = future::join_all(definitions)
16794                .await
16795                .into_iter()
16796                .filter_map(|location| location.transpose())
16797                .collect::<Result<_>>()
16798                .context("location tasks")?;
16799            let mut locations = cx.update(|_, cx| {
16800                locations
16801                    .into_iter()
16802                    .map(|location| {
16803                        let buffer = location.buffer.read(cx);
16804                        (location.buffer, location.range.to_point(buffer))
16805                    })
16806                    .into_group_map()
16807            })?;
16808            let mut num_locations = 0;
16809            for ranges in locations.values_mut() {
16810                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
16811                ranges.dedup();
16812                num_locations += ranges.len();
16813            }
16814
16815            if num_locations > 1 {
16816                let Some(workspace) = workspace else {
16817                    return Ok(Navigated::No);
16818                };
16819
16820                let tab_kind = match kind {
16821                    Some(GotoDefinitionKind::Implementation) => "Implementations",
16822                    Some(GotoDefinitionKind::Symbol) | None => "Definitions",
16823                    Some(GotoDefinitionKind::Declaration) => "Declarations",
16824                    Some(GotoDefinitionKind::Type) => "Types",
16825                };
16826                let title = editor
16827                    .update_in(cx, |_, _, cx| {
16828                        let target = locations
16829                            .iter()
16830                            .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
16831                            .map(|(buffer, location)| {
16832                                buffer
16833                                    .read(cx)
16834                                    .text_for_range(location.clone())
16835                                    .collect::<String>()
16836                            })
16837                            .filter(|text| !text.contains('\n'))
16838                            .unique()
16839                            .take(3)
16840                            .join(", ");
16841                        if target.is_empty() {
16842                            tab_kind.to_owned()
16843                        } else {
16844                            format!("{tab_kind} for {target}")
16845                        }
16846                    })
16847                    .context("buffer title")?;
16848
16849                let opened = workspace
16850                    .update_in(cx, |workspace, window, cx| {
16851                        Self::open_locations_in_multibuffer(
16852                            workspace,
16853                            locations,
16854                            title,
16855                            split,
16856                            MultibufferSelectionMode::First,
16857                            window,
16858                            cx,
16859                        )
16860                    })
16861                    .is_ok();
16862
16863                anyhow::Ok(Navigated::from_bool(opened))
16864            } else if num_locations == 0 {
16865                // If there is one url or file, open it directly
16866                match first_url_or_file {
16867                    Some(Either::Left(url)) => {
16868                        cx.update(|_, cx| cx.open_url(&url))?;
16869                        Ok(Navigated::Yes)
16870                    }
16871                    Some(Either::Right(path)) => {
16872                        let Some(workspace) = workspace else {
16873                            return Ok(Navigated::No);
16874                        };
16875
16876                        workspace
16877                            .update_in(cx, |workspace, window, cx| {
16878                                workspace.open_resolved_path(path, window, cx)
16879                            })?
16880                            .await?;
16881                        Ok(Navigated::Yes)
16882                    }
16883                    None => Ok(Navigated::No),
16884                }
16885            } else {
16886                let Some(workspace) = workspace else {
16887                    return Ok(Navigated::No);
16888                };
16889
16890                let (target_buffer, target_ranges) = locations.into_iter().next().unwrap();
16891                let target_range = target_ranges.first().unwrap().clone();
16892
16893                editor.update_in(cx, |editor, window, cx| {
16894                    let range = target_range.to_point(target_buffer.read(cx));
16895                    let range = editor.range_for_match(&range);
16896                    let range = collapse_multiline_range(range);
16897
16898                    if !split
16899                        && Some(&target_buffer) == editor.buffer.read(cx).as_singleton().as_ref()
16900                    {
16901                        editor.go_to_singleton_buffer_range(range, window, cx);
16902                    } else {
16903                        let pane = workspace.read(cx).active_pane().clone();
16904                        window.defer(cx, move |window, cx| {
16905                            let target_editor: Entity<Self> =
16906                                workspace.update(cx, |workspace, cx| {
16907                                    let pane = if split {
16908                                        workspace.adjacent_pane(window, cx)
16909                                    } else {
16910                                        workspace.active_pane().clone()
16911                                    };
16912
16913                                    workspace.open_project_item(
16914                                        pane,
16915                                        target_buffer.clone(),
16916                                        true,
16917                                        true,
16918                                        window,
16919                                        cx,
16920                                    )
16921                                });
16922                            target_editor.update(cx, |target_editor, cx| {
16923                                // When selecting a definition in a different buffer, disable the nav history
16924                                // to avoid creating a history entry at the previous cursor location.
16925                                pane.update(cx, |pane, _| pane.disable_history());
16926                                target_editor.go_to_singleton_buffer_range(range, window, cx);
16927                                pane.update(cx, |pane, _| pane.enable_history());
16928                            });
16929                        });
16930                    }
16931                    Navigated::Yes
16932                })
16933            }
16934        })
16935    }
16936
16937    fn compute_target_location(
16938        &self,
16939        lsp_location: lsp::Location,
16940        server_id: LanguageServerId,
16941        window: &mut Window,
16942        cx: &mut Context<Self>,
16943    ) -> Task<anyhow::Result<Option<Location>>> {
16944        let Some(project) = self.project.clone() else {
16945            return Task::ready(Ok(None));
16946        };
16947
16948        cx.spawn_in(window, async move |editor, cx| {
16949            let location_task = editor.update(cx, |_, cx| {
16950                project.update(cx, |project, cx| {
16951                    project.open_local_buffer_via_lsp(lsp_location.uri.clone(), server_id, cx)
16952                })
16953            })?;
16954            let location = Some({
16955                let target_buffer_handle = location_task.await.context("open local buffer")?;
16956                let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
16957                    let target_start = target_buffer
16958                        .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
16959                    let target_end = target_buffer
16960                        .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
16961                    target_buffer.anchor_after(target_start)
16962                        ..target_buffer.anchor_before(target_end)
16963                })?;
16964                Location {
16965                    buffer: target_buffer_handle,
16966                    range,
16967                }
16968            });
16969            Ok(location)
16970        })
16971    }
16972
16973    fn go_to_next_reference(
16974        &mut self,
16975        _: &GoToNextReference,
16976        window: &mut Window,
16977        cx: &mut Context<Self>,
16978    ) {
16979        let task = self.go_to_reference_before_or_after_position(Direction::Next, 1, window, cx);
16980        if let Some(task) = task {
16981            task.detach();
16982        };
16983    }
16984
16985    fn go_to_prev_reference(
16986        &mut self,
16987        _: &GoToPreviousReference,
16988        window: &mut Window,
16989        cx: &mut Context<Self>,
16990    ) {
16991        let task = self.go_to_reference_before_or_after_position(Direction::Prev, 1, window, cx);
16992        if let Some(task) = task {
16993            task.detach();
16994        };
16995    }
16996
16997    pub fn go_to_reference_before_or_after_position(
16998        &mut self,
16999        direction: Direction,
17000        count: usize,
17001        window: &mut Window,
17002        cx: &mut Context<Self>,
17003    ) -> Option<Task<Result<()>>> {
17004        let selection = self.selections.newest_anchor();
17005        let head = selection.head();
17006
17007        let multi_buffer = self.buffer.read(cx);
17008
17009        let (buffer, text_head) = multi_buffer.text_anchor_for_position(head, cx)?;
17010        let workspace = self.workspace()?;
17011        let project = workspace.read(cx).project().clone();
17012        let references =
17013            project.update(cx, |project, cx| project.references(&buffer, text_head, cx));
17014        Some(cx.spawn_in(window, async move |editor, cx| -> Result<()> {
17015            let Some(locations) = references.await? else {
17016                return Ok(());
17017            };
17018
17019            if locations.is_empty() {
17020                // totally normal - the cursor may be on something which is not
17021                // a symbol (e.g. a keyword)
17022                log::info!("no references found under cursor");
17023                return Ok(());
17024            }
17025
17026            let multi_buffer = editor.read_with(cx, |editor, _| editor.buffer().clone())?;
17027
17028            let multi_buffer_snapshot =
17029                multi_buffer.read_with(cx, |multi_buffer, cx| multi_buffer.snapshot(cx))?;
17030
17031            let (locations, current_location_index) =
17032                multi_buffer.update(cx, |multi_buffer, cx| {
17033                    let mut locations = locations
17034                        .into_iter()
17035                        .filter_map(|loc| {
17036                            let start = multi_buffer.buffer_anchor_to_anchor(
17037                                &loc.buffer,
17038                                loc.range.start,
17039                                cx,
17040                            )?;
17041                            let end = multi_buffer.buffer_anchor_to_anchor(
17042                                &loc.buffer,
17043                                loc.range.end,
17044                                cx,
17045                            )?;
17046                            Some(start..end)
17047                        })
17048                        .collect::<Vec<_>>();
17049
17050                    // There is an O(n) implementation, but given this list will be
17051                    // small (usually <100 items), the extra O(log(n)) factor isn't
17052                    // worth the (surprisingly large amount of) extra complexity.
17053                    locations
17054                        .sort_unstable_by(|l, r| l.start.cmp(&r.start, &multi_buffer_snapshot));
17055
17056                    let head_offset = head.to_offset(&multi_buffer_snapshot);
17057
17058                    let current_location_index = locations.iter().position(|loc| {
17059                        loc.start.to_offset(&multi_buffer_snapshot) <= head_offset
17060                            && loc.end.to_offset(&multi_buffer_snapshot) >= head_offset
17061                    });
17062
17063                    (locations, current_location_index)
17064                })?;
17065
17066            let Some(current_location_index) = current_location_index else {
17067                // This indicates something has gone wrong, because we already
17068                // handle the "no references" case above
17069                log::error!(
17070                    "failed to find current reference under cursor. Total references: {}",
17071                    locations.len()
17072                );
17073                return Ok(());
17074            };
17075
17076            let destination_location_index = match direction {
17077                Direction::Next => (current_location_index + count) % locations.len(),
17078                Direction::Prev => {
17079                    (current_location_index + locations.len() - count % locations.len())
17080                        % locations.len()
17081                }
17082            };
17083
17084            // TODO(cameron): is this needed?
17085            // the thinking is to avoid "jumping to the current location" (avoid
17086            // polluting "jumplist" in vim terms)
17087            if current_location_index == destination_location_index {
17088                return Ok(());
17089            }
17090
17091            let Range { start, end } = locations[destination_location_index];
17092
17093            editor.update_in(cx, |editor, window, cx| {
17094                let effects = SelectionEffects::default();
17095
17096                editor.unfold_ranges(&[start..end], false, false, cx);
17097                editor.change_selections(effects, window, cx, |s| {
17098                    s.select_ranges([start..start]);
17099                });
17100            })?;
17101
17102            Ok(())
17103        }))
17104    }
17105
17106    pub fn find_all_references(
17107        &mut self,
17108        _: &FindAllReferences,
17109        window: &mut Window,
17110        cx: &mut Context<Self>,
17111    ) -> Option<Task<Result<Navigated>>> {
17112        let selection = self.selections.newest::<usize>(&self.display_snapshot(cx));
17113        let multi_buffer = self.buffer.read(cx);
17114        let head = selection.head();
17115
17116        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
17117        let head_anchor = multi_buffer_snapshot.anchor_at(
17118            head,
17119            if head < selection.tail() {
17120                Bias::Right
17121            } else {
17122                Bias::Left
17123            },
17124        );
17125
17126        match self
17127            .find_all_references_task_sources
17128            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
17129        {
17130            Ok(_) => {
17131                log::info!(
17132                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
17133                );
17134                return None;
17135            }
17136            Err(i) => {
17137                self.find_all_references_task_sources.insert(i, head_anchor);
17138            }
17139        }
17140
17141        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
17142        let workspace = self.workspace()?;
17143        let project = workspace.read(cx).project().clone();
17144        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
17145        Some(cx.spawn_in(window, async move |editor, cx| {
17146            let _cleanup = cx.on_drop(&editor, move |editor, _| {
17147                if let Ok(i) = editor
17148                    .find_all_references_task_sources
17149                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
17150                {
17151                    editor.find_all_references_task_sources.remove(i);
17152                }
17153            });
17154
17155            let Some(locations) = references.await? else {
17156                return anyhow::Ok(Navigated::No);
17157            };
17158            let mut locations = cx.update(|_, cx| {
17159                locations
17160                    .into_iter()
17161                    .map(|location| {
17162                        let buffer = location.buffer.read(cx);
17163                        (location.buffer, location.range.to_point(buffer))
17164                    })
17165                    .into_group_map()
17166            })?;
17167            if locations.is_empty() {
17168                return anyhow::Ok(Navigated::No);
17169            }
17170            for ranges in locations.values_mut() {
17171                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
17172                ranges.dedup();
17173            }
17174
17175            workspace.update_in(cx, |workspace, window, cx| {
17176                let target = locations
17177                    .iter()
17178                    .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
17179                    .map(|(buffer, location)| {
17180                        buffer
17181                            .read(cx)
17182                            .text_for_range(location.clone())
17183                            .collect::<String>()
17184                    })
17185                    .filter(|text| !text.contains('\n'))
17186                    .unique()
17187                    .take(3)
17188                    .join(", ");
17189                let title = if target.is_empty() {
17190                    "References".to_owned()
17191                } else {
17192                    format!("References to {target}")
17193                };
17194                Self::open_locations_in_multibuffer(
17195                    workspace,
17196                    locations,
17197                    title,
17198                    false,
17199                    MultibufferSelectionMode::First,
17200                    window,
17201                    cx,
17202                );
17203                Navigated::Yes
17204            })
17205        }))
17206    }
17207
17208    /// Opens a multibuffer with the given project locations in it
17209    pub fn open_locations_in_multibuffer(
17210        workspace: &mut Workspace,
17211        locations: std::collections::HashMap<Entity<Buffer>, Vec<Range<Point>>>,
17212        title: String,
17213        split: bool,
17214        multibuffer_selection_mode: MultibufferSelectionMode,
17215        window: &mut Window,
17216        cx: &mut Context<Workspace>,
17217    ) {
17218        if locations.is_empty() {
17219            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
17220            return;
17221        }
17222
17223        let capability = workspace.project().read(cx).capability();
17224        let mut ranges = <Vec<Range<Anchor>>>::new();
17225
17226        // a key to find existing multibuffer editors with the same set of locations
17227        // to prevent us from opening more and more multibuffer tabs for searches and the like
17228        let mut key = (title.clone(), vec![]);
17229        let excerpt_buffer = cx.new(|cx| {
17230            let key = &mut key.1;
17231            let mut multibuffer = MultiBuffer::new(capability);
17232            for (buffer, mut ranges_for_buffer) in locations {
17233                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
17234                key.push((buffer.read(cx).remote_id(), ranges_for_buffer.clone()));
17235                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
17236                    PathKey::for_buffer(&buffer, cx),
17237                    buffer.clone(),
17238                    ranges_for_buffer,
17239                    multibuffer_context_lines(cx),
17240                    cx,
17241                );
17242                ranges.extend(new_ranges)
17243            }
17244
17245            multibuffer.with_title(title)
17246        });
17247        let existing = workspace.active_pane().update(cx, |pane, cx| {
17248            pane.items()
17249                .filter_map(|item| item.downcast::<Editor>())
17250                .find(|editor| {
17251                    editor
17252                        .read(cx)
17253                        .lookup_key
17254                        .as_ref()
17255                        .and_then(|it| {
17256                            it.downcast_ref::<(String, Vec<(BufferId, Vec<Range<Point>>)>)>()
17257                        })
17258                        .is_some_and(|it| *it == key)
17259                })
17260        });
17261        let editor = existing.unwrap_or_else(|| {
17262            cx.new(|cx| {
17263                let mut editor = Editor::for_multibuffer(
17264                    excerpt_buffer,
17265                    Some(workspace.project().clone()),
17266                    window,
17267                    cx,
17268                );
17269                editor.lookup_key = Some(Box::new(key));
17270                editor
17271            })
17272        });
17273        editor.update(cx, |editor, cx| match multibuffer_selection_mode {
17274            MultibufferSelectionMode::First => {
17275                if let Some(first_range) = ranges.first() {
17276                    editor.change_selections(
17277                        SelectionEffects::no_scroll(),
17278                        window,
17279                        cx,
17280                        |selections| {
17281                            selections.clear_disjoint();
17282                            selections.select_anchor_ranges(std::iter::once(first_range.clone()));
17283                        },
17284                    );
17285                }
17286                editor.highlight_background::<Self>(
17287                    &ranges,
17288                    |theme| theme.colors().editor_highlighted_line_background,
17289                    cx,
17290                );
17291            }
17292            MultibufferSelectionMode::All => {
17293                editor.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
17294                    selections.clear_disjoint();
17295                    selections.select_anchor_ranges(ranges);
17296                });
17297            }
17298        });
17299
17300        let item = Box::new(editor);
17301        let item_id = item.item_id();
17302
17303        if split {
17304            let pane = workspace.adjacent_pane(window, cx);
17305            workspace.add_item(pane, item, None, true, true, window, cx);
17306        } else if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
17307            let (preview_item_id, preview_item_idx) =
17308                workspace.active_pane().read_with(cx, |pane, _| {
17309                    (pane.preview_item_id(), pane.preview_item_idx())
17310                });
17311
17312            workspace.add_item_to_active_pane(item, preview_item_idx, true, window, cx);
17313
17314            if let Some(preview_item_id) = preview_item_id {
17315                workspace.active_pane().update(cx, |pane, cx| {
17316                    pane.remove_item(preview_item_id, false, false, window, cx);
17317                });
17318            }
17319        } else {
17320            workspace.add_item_to_active_pane(item, None, true, window, cx);
17321        }
17322        workspace.active_pane().update(cx, |pane, cx| {
17323            pane.set_preview_item_id(Some(item_id), cx);
17324        });
17325    }
17326
17327    pub fn rename(
17328        &mut self,
17329        _: &Rename,
17330        window: &mut Window,
17331        cx: &mut Context<Self>,
17332    ) -> Option<Task<Result<()>>> {
17333        use language::ToOffset as _;
17334
17335        let provider = self.semantics_provider.clone()?;
17336        let selection = self.selections.newest_anchor().clone();
17337        let (cursor_buffer, cursor_buffer_position) = self
17338            .buffer
17339            .read(cx)
17340            .text_anchor_for_position(selection.head(), cx)?;
17341        let (tail_buffer, cursor_buffer_position_end) = self
17342            .buffer
17343            .read(cx)
17344            .text_anchor_for_position(selection.tail(), cx)?;
17345        if tail_buffer != cursor_buffer {
17346            return None;
17347        }
17348
17349        let snapshot = cursor_buffer.read(cx).snapshot();
17350        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
17351        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
17352        let prepare_rename = provider
17353            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
17354            .unwrap_or_else(|| Task::ready(Ok(None)));
17355        drop(snapshot);
17356
17357        Some(cx.spawn_in(window, async move |this, cx| {
17358            let rename_range = if let Some(range) = prepare_rename.await? {
17359                Some(range)
17360            } else {
17361                this.update(cx, |this, cx| {
17362                    let buffer = this.buffer.read(cx).snapshot(cx);
17363                    let mut buffer_highlights = this
17364                        .document_highlights_for_position(selection.head(), &buffer)
17365                        .filter(|highlight| {
17366                            highlight.start.excerpt_id == selection.head().excerpt_id
17367                                && highlight.end.excerpt_id == selection.head().excerpt_id
17368                        });
17369                    buffer_highlights
17370                        .next()
17371                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
17372                })?
17373            };
17374            if let Some(rename_range) = rename_range {
17375                this.update_in(cx, |this, window, cx| {
17376                    let snapshot = cursor_buffer.read(cx).snapshot();
17377                    let rename_buffer_range = rename_range.to_offset(&snapshot);
17378                    let cursor_offset_in_rename_range =
17379                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
17380                    let cursor_offset_in_rename_range_end =
17381                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
17382
17383                    this.take_rename(false, window, cx);
17384                    let buffer = this.buffer.read(cx).read(cx);
17385                    let cursor_offset = selection.head().to_offset(&buffer);
17386                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
17387                    let rename_end = rename_start + rename_buffer_range.len();
17388                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
17389                    let mut old_highlight_id = None;
17390                    let old_name: Arc<str> = buffer
17391                        .chunks(rename_start..rename_end, true)
17392                        .map(|chunk| {
17393                            if old_highlight_id.is_none() {
17394                                old_highlight_id = chunk.syntax_highlight_id;
17395                            }
17396                            chunk.text
17397                        })
17398                        .collect::<String>()
17399                        .into();
17400
17401                    drop(buffer);
17402
17403                    // Position the selection in the rename editor so that it matches the current selection.
17404                    this.show_local_selections = false;
17405                    let rename_editor = cx.new(|cx| {
17406                        let mut editor = Editor::single_line(window, cx);
17407                        editor.buffer.update(cx, |buffer, cx| {
17408                            buffer.edit([(0..0, old_name.clone())], None, cx)
17409                        });
17410                        let rename_selection_range = match cursor_offset_in_rename_range
17411                            .cmp(&cursor_offset_in_rename_range_end)
17412                        {
17413                            Ordering::Equal => {
17414                                editor.select_all(&SelectAll, window, cx);
17415                                return editor;
17416                            }
17417                            Ordering::Less => {
17418                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
17419                            }
17420                            Ordering::Greater => {
17421                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
17422                            }
17423                        };
17424                        if rename_selection_range.end > old_name.len() {
17425                            editor.select_all(&SelectAll, window, cx);
17426                        } else {
17427                            editor.change_selections(Default::default(), window, cx, |s| {
17428                                s.select_ranges([rename_selection_range]);
17429                            });
17430                        }
17431                        editor
17432                    });
17433                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
17434                        if e == &EditorEvent::Focused {
17435                            cx.emit(EditorEvent::FocusedIn)
17436                        }
17437                    })
17438                    .detach();
17439
17440                    let write_highlights =
17441                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
17442                    let read_highlights =
17443                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
17444                    let ranges = write_highlights
17445                        .iter()
17446                        .flat_map(|(_, ranges)| ranges.iter())
17447                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
17448                        .cloned()
17449                        .collect();
17450
17451                    this.highlight_text::<Rename>(
17452                        ranges,
17453                        HighlightStyle {
17454                            fade_out: Some(0.6),
17455                            ..Default::default()
17456                        },
17457                        cx,
17458                    );
17459                    let rename_focus_handle = rename_editor.focus_handle(cx);
17460                    window.focus(&rename_focus_handle);
17461                    let block_id = this.insert_blocks(
17462                        [BlockProperties {
17463                            style: BlockStyle::Flex,
17464                            placement: BlockPlacement::Below(range.start),
17465                            height: Some(1),
17466                            render: Arc::new({
17467                                let rename_editor = rename_editor.clone();
17468                                move |cx: &mut BlockContext| {
17469                                    let mut text_style = cx.editor_style.text.clone();
17470                                    if let Some(highlight_style) = old_highlight_id
17471                                        .and_then(|h| h.style(&cx.editor_style.syntax))
17472                                    {
17473                                        text_style = text_style.highlight(highlight_style);
17474                                    }
17475                                    div()
17476                                        .block_mouse_except_scroll()
17477                                        .pl(cx.anchor_x)
17478                                        .child(EditorElement::new(
17479                                            &rename_editor,
17480                                            EditorStyle {
17481                                                background: cx.theme().system().transparent,
17482                                                local_player: cx.editor_style.local_player,
17483                                                text: text_style,
17484                                                scrollbar_width: cx.editor_style.scrollbar_width,
17485                                                syntax: cx.editor_style.syntax.clone(),
17486                                                status: cx.editor_style.status.clone(),
17487                                                inlay_hints_style: HighlightStyle {
17488                                                    font_weight: Some(FontWeight::BOLD),
17489                                                    ..make_inlay_hints_style(cx.app)
17490                                                },
17491                                                edit_prediction_styles: make_suggestion_styles(
17492                                                    cx.app,
17493                                                ),
17494                                                ..EditorStyle::default()
17495                                            },
17496                                        ))
17497                                        .into_any_element()
17498                                }
17499                            }),
17500                            priority: 0,
17501                        }],
17502                        Some(Autoscroll::fit()),
17503                        cx,
17504                    )[0];
17505                    this.pending_rename = Some(RenameState {
17506                        range,
17507                        old_name,
17508                        editor: rename_editor,
17509                        block_id,
17510                    });
17511                })?;
17512            }
17513
17514            Ok(())
17515        }))
17516    }
17517
17518    pub fn confirm_rename(
17519        &mut self,
17520        _: &ConfirmRename,
17521        window: &mut Window,
17522        cx: &mut Context<Self>,
17523    ) -> Option<Task<Result<()>>> {
17524        let rename = self.take_rename(false, window, cx)?;
17525        let workspace = self.workspace()?.downgrade();
17526        let (buffer, start) = self
17527            .buffer
17528            .read(cx)
17529            .text_anchor_for_position(rename.range.start, cx)?;
17530        let (end_buffer, _) = self
17531            .buffer
17532            .read(cx)
17533            .text_anchor_for_position(rename.range.end, cx)?;
17534        if buffer != end_buffer {
17535            return None;
17536        }
17537
17538        let old_name = rename.old_name;
17539        let new_name = rename.editor.read(cx).text(cx);
17540
17541        let rename = self.semantics_provider.as_ref()?.perform_rename(
17542            &buffer,
17543            start,
17544            new_name.clone(),
17545            cx,
17546        )?;
17547
17548        Some(cx.spawn_in(window, async move |editor, cx| {
17549            let project_transaction = rename.await?;
17550            Self::open_project_transaction(
17551                &editor,
17552                workspace,
17553                project_transaction,
17554                format!("Rename: {}{}", old_name, new_name),
17555                cx,
17556            )
17557            .await?;
17558
17559            editor.update(cx, |editor, cx| {
17560                editor.refresh_document_highlights(cx);
17561            })?;
17562            Ok(())
17563        }))
17564    }
17565
17566    fn take_rename(
17567        &mut self,
17568        moving_cursor: bool,
17569        window: &mut Window,
17570        cx: &mut Context<Self>,
17571    ) -> Option<RenameState> {
17572        let rename = self.pending_rename.take()?;
17573        if rename.editor.focus_handle(cx).is_focused(window) {
17574            window.focus(&self.focus_handle);
17575        }
17576
17577        self.remove_blocks(
17578            [rename.block_id].into_iter().collect(),
17579            Some(Autoscroll::fit()),
17580            cx,
17581        );
17582        self.clear_highlights::<Rename>(cx);
17583        self.show_local_selections = true;
17584
17585        if moving_cursor {
17586            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
17587                editor
17588                    .selections
17589                    .newest::<usize>(&editor.display_snapshot(cx))
17590                    .head()
17591            });
17592
17593            // Update the selection to match the position of the selection inside
17594            // the rename editor.
17595            let snapshot = self.buffer.read(cx).read(cx);
17596            let rename_range = rename.range.to_offset(&snapshot);
17597            let cursor_in_editor = snapshot
17598                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
17599                .min(rename_range.end);
17600            drop(snapshot);
17601
17602            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17603                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
17604            });
17605        } else {
17606            self.refresh_document_highlights(cx);
17607        }
17608
17609        Some(rename)
17610    }
17611
17612    pub fn pending_rename(&self) -> Option<&RenameState> {
17613        self.pending_rename.as_ref()
17614    }
17615
17616    fn format(
17617        &mut self,
17618        _: &Format,
17619        window: &mut Window,
17620        cx: &mut Context<Self>,
17621    ) -> Option<Task<Result<()>>> {
17622        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17623
17624        let project = match &self.project {
17625            Some(project) => project.clone(),
17626            None => return None,
17627        };
17628
17629        Some(self.perform_format(
17630            project,
17631            FormatTrigger::Manual,
17632            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
17633            window,
17634            cx,
17635        ))
17636    }
17637
17638    fn format_selections(
17639        &mut self,
17640        _: &FormatSelections,
17641        window: &mut Window,
17642        cx: &mut Context<Self>,
17643    ) -> Option<Task<Result<()>>> {
17644        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17645
17646        let project = match &self.project {
17647            Some(project) => project.clone(),
17648            None => return None,
17649        };
17650
17651        let ranges = self
17652            .selections
17653            .all_adjusted(&self.display_snapshot(cx))
17654            .into_iter()
17655            .map(|selection| selection.range())
17656            .collect_vec();
17657
17658        Some(self.perform_format(
17659            project,
17660            FormatTrigger::Manual,
17661            FormatTarget::Ranges(ranges),
17662            window,
17663            cx,
17664        ))
17665    }
17666
17667    fn perform_format(
17668        &mut self,
17669        project: Entity<Project>,
17670        trigger: FormatTrigger,
17671        target: FormatTarget,
17672        window: &mut Window,
17673        cx: &mut Context<Self>,
17674    ) -> Task<Result<()>> {
17675        let buffer = self.buffer.clone();
17676        let (buffers, target) = match target {
17677            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
17678            FormatTarget::Ranges(selection_ranges) => {
17679                let multi_buffer = buffer.read(cx);
17680                let snapshot = multi_buffer.read(cx);
17681                let mut buffers = HashSet::default();
17682                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
17683                    BTreeMap::new();
17684                for selection_range in selection_ranges {
17685                    for (buffer, buffer_range, _) in
17686                        snapshot.range_to_buffer_ranges(selection_range)
17687                    {
17688                        let buffer_id = buffer.remote_id();
17689                        let start = buffer.anchor_before(buffer_range.start);
17690                        let end = buffer.anchor_after(buffer_range.end);
17691                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
17692                        buffer_id_to_ranges
17693                            .entry(buffer_id)
17694                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
17695                            .or_insert_with(|| vec![start..end]);
17696                    }
17697                }
17698                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
17699            }
17700        };
17701
17702        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
17703        let selections_prev = transaction_id_prev
17704            .and_then(|transaction_id_prev| {
17705                // default to selections as they were after the last edit, if we have them,
17706                // instead of how they are now.
17707                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
17708                // will take you back to where you made the last edit, instead of staying where you scrolled
17709                self.selection_history
17710                    .transaction(transaction_id_prev)
17711                    .map(|t| t.0.clone())
17712            })
17713            .unwrap_or_else(|| self.selections.disjoint_anchors_arc());
17714
17715        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
17716        let format = project.update(cx, |project, cx| {
17717            project.format(buffers, target, true, trigger, cx)
17718        });
17719
17720        cx.spawn_in(window, async move |editor, cx| {
17721            let transaction = futures::select_biased! {
17722                transaction = format.log_err().fuse() => transaction,
17723                () = timeout => {
17724                    log::warn!("timed out waiting for formatting");
17725                    None
17726                }
17727            };
17728
17729            buffer
17730                .update(cx, |buffer, cx| {
17731                    if let Some(transaction) = transaction
17732                        && !buffer.is_singleton()
17733                    {
17734                        buffer.push_transaction(&transaction.0, cx);
17735                    }
17736                    cx.notify();
17737                })
17738                .ok();
17739
17740            if let Some(transaction_id_now) =
17741                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
17742            {
17743                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
17744                if has_new_transaction {
17745                    _ = editor.update(cx, |editor, _| {
17746                        editor
17747                            .selection_history
17748                            .insert_transaction(transaction_id_now, selections_prev);
17749                    });
17750                }
17751            }
17752
17753            Ok(())
17754        })
17755    }
17756
17757    fn organize_imports(
17758        &mut self,
17759        _: &OrganizeImports,
17760        window: &mut Window,
17761        cx: &mut Context<Self>,
17762    ) -> Option<Task<Result<()>>> {
17763        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17764        let project = match &self.project {
17765            Some(project) => project.clone(),
17766            None => return None,
17767        };
17768        Some(self.perform_code_action_kind(
17769            project,
17770            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
17771            window,
17772            cx,
17773        ))
17774    }
17775
17776    fn perform_code_action_kind(
17777        &mut self,
17778        project: Entity<Project>,
17779        kind: CodeActionKind,
17780        window: &mut Window,
17781        cx: &mut Context<Self>,
17782    ) -> Task<Result<()>> {
17783        let buffer = self.buffer.clone();
17784        let buffers = buffer.read(cx).all_buffers();
17785        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
17786        let apply_action = project.update(cx, |project, cx| {
17787            project.apply_code_action_kind(buffers, kind, true, cx)
17788        });
17789        cx.spawn_in(window, async move |_, cx| {
17790            let transaction = futures::select_biased! {
17791                () = timeout => {
17792                    log::warn!("timed out waiting for executing code action");
17793                    None
17794                }
17795                transaction = apply_action.log_err().fuse() => transaction,
17796            };
17797            buffer
17798                .update(cx, |buffer, cx| {
17799                    // check if we need this
17800                    if let Some(transaction) = transaction
17801                        && !buffer.is_singleton()
17802                    {
17803                        buffer.push_transaction(&transaction.0, cx);
17804                    }
17805                    cx.notify();
17806                })
17807                .ok();
17808            Ok(())
17809        })
17810    }
17811
17812    pub fn restart_language_server(
17813        &mut self,
17814        _: &RestartLanguageServer,
17815        _: &mut Window,
17816        cx: &mut Context<Self>,
17817    ) {
17818        if let Some(project) = self.project.clone() {
17819            self.buffer.update(cx, |multi_buffer, cx| {
17820                project.update(cx, |project, cx| {
17821                    project.restart_language_servers_for_buffers(
17822                        multi_buffer.all_buffers().into_iter().collect(),
17823                        HashSet::default(),
17824                        cx,
17825                    );
17826                });
17827            })
17828        }
17829    }
17830
17831    pub fn stop_language_server(
17832        &mut self,
17833        _: &StopLanguageServer,
17834        _: &mut Window,
17835        cx: &mut Context<Self>,
17836    ) {
17837        if let Some(project) = self.project.clone() {
17838            self.buffer.update(cx, |multi_buffer, cx| {
17839                project.update(cx, |project, cx| {
17840                    project.stop_language_servers_for_buffers(
17841                        multi_buffer.all_buffers().into_iter().collect(),
17842                        HashSet::default(),
17843                        cx,
17844                    );
17845                });
17846            });
17847            self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
17848        }
17849    }
17850
17851    fn cancel_language_server_work(
17852        workspace: &mut Workspace,
17853        _: &actions::CancelLanguageServerWork,
17854        _: &mut Window,
17855        cx: &mut Context<Workspace>,
17856    ) {
17857        let project = workspace.project();
17858        let buffers = workspace
17859            .active_item(cx)
17860            .and_then(|item| item.act_as::<Editor>(cx))
17861            .map_or(HashSet::default(), |editor| {
17862                editor.read(cx).buffer.read(cx).all_buffers()
17863            });
17864        project.update(cx, |project, cx| {
17865            project.cancel_language_server_work_for_buffers(buffers, cx);
17866        });
17867    }
17868
17869    fn show_character_palette(
17870        &mut self,
17871        _: &ShowCharacterPalette,
17872        window: &mut Window,
17873        _: &mut Context<Self>,
17874    ) {
17875        window.show_character_palette();
17876    }
17877
17878    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
17879        if !self.diagnostics_enabled() {
17880            return;
17881        }
17882
17883        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
17884            let buffer = self.buffer.read(cx).snapshot(cx);
17885            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
17886            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
17887            let is_valid = buffer
17888                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
17889                .any(|entry| {
17890                    entry.diagnostic.is_primary
17891                        && !entry.range.is_empty()
17892                        && entry.range.start == primary_range_start
17893                        && entry.diagnostic.message == active_diagnostics.active_message
17894                });
17895
17896            if !is_valid {
17897                self.dismiss_diagnostics(cx);
17898            }
17899        }
17900    }
17901
17902    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
17903        match &self.active_diagnostics {
17904            ActiveDiagnostic::Group(group) => Some(group),
17905            _ => None,
17906        }
17907    }
17908
17909    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
17910        if !self.diagnostics_enabled() {
17911            return;
17912        }
17913        self.dismiss_diagnostics(cx);
17914        self.active_diagnostics = ActiveDiagnostic::All;
17915    }
17916
17917    fn activate_diagnostics(
17918        &mut self,
17919        buffer_id: BufferId,
17920        diagnostic: DiagnosticEntryRef<'_, usize>,
17921        window: &mut Window,
17922        cx: &mut Context<Self>,
17923    ) {
17924        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
17925            return;
17926        }
17927        self.dismiss_diagnostics(cx);
17928        let snapshot = self.snapshot(window, cx);
17929        let buffer = self.buffer.read(cx).snapshot(cx);
17930        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
17931            return;
17932        };
17933
17934        let diagnostic_group = buffer
17935            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
17936            .collect::<Vec<_>>();
17937
17938        let blocks =
17939            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
17940
17941        let blocks = self.display_map.update(cx, |display_map, cx| {
17942            display_map.insert_blocks(blocks, cx).into_iter().collect()
17943        });
17944        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
17945            active_range: buffer.anchor_before(diagnostic.range.start)
17946                ..buffer.anchor_after(diagnostic.range.end),
17947            active_message: diagnostic.diagnostic.message.clone(),
17948            group_id: diagnostic.diagnostic.group_id,
17949            blocks,
17950        });
17951        cx.notify();
17952    }
17953
17954    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
17955        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
17956            return;
17957        };
17958
17959        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
17960        if let ActiveDiagnostic::Group(group) = prev {
17961            self.display_map.update(cx, |display_map, cx| {
17962                display_map.remove_blocks(group.blocks, cx);
17963            });
17964            cx.notify();
17965        }
17966    }
17967
17968    /// Disable inline diagnostics rendering for this editor.
17969    pub fn disable_inline_diagnostics(&mut self) {
17970        self.inline_diagnostics_enabled = false;
17971        self.inline_diagnostics_update = Task::ready(());
17972        self.inline_diagnostics.clear();
17973    }
17974
17975    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
17976        self.diagnostics_enabled = false;
17977        self.dismiss_diagnostics(cx);
17978        self.inline_diagnostics_update = Task::ready(());
17979        self.inline_diagnostics.clear();
17980    }
17981
17982    pub fn disable_word_completions(&mut self) {
17983        self.word_completions_enabled = false;
17984    }
17985
17986    pub fn diagnostics_enabled(&self) -> bool {
17987        self.diagnostics_enabled && self.mode.is_full()
17988    }
17989
17990    pub fn inline_diagnostics_enabled(&self) -> bool {
17991        self.inline_diagnostics_enabled && self.diagnostics_enabled()
17992    }
17993
17994    pub fn show_inline_diagnostics(&self) -> bool {
17995        self.show_inline_diagnostics
17996    }
17997
17998    pub fn toggle_inline_diagnostics(
17999        &mut self,
18000        _: &ToggleInlineDiagnostics,
18001        window: &mut Window,
18002        cx: &mut Context<Editor>,
18003    ) {
18004        self.show_inline_diagnostics = !self.show_inline_diagnostics;
18005        self.refresh_inline_diagnostics(false, window, cx);
18006    }
18007
18008    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
18009        self.diagnostics_max_severity = severity;
18010        self.display_map.update(cx, |display_map, _| {
18011            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
18012        });
18013    }
18014
18015    pub fn toggle_diagnostics(
18016        &mut self,
18017        _: &ToggleDiagnostics,
18018        window: &mut Window,
18019        cx: &mut Context<Editor>,
18020    ) {
18021        if !self.diagnostics_enabled() {
18022            return;
18023        }
18024
18025        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
18026            EditorSettings::get_global(cx)
18027                .diagnostics_max_severity
18028                .filter(|severity| severity != &DiagnosticSeverity::Off)
18029                .unwrap_or(DiagnosticSeverity::Hint)
18030        } else {
18031            DiagnosticSeverity::Off
18032        };
18033        self.set_max_diagnostics_severity(new_severity, cx);
18034        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
18035            self.active_diagnostics = ActiveDiagnostic::None;
18036            self.inline_diagnostics_update = Task::ready(());
18037            self.inline_diagnostics.clear();
18038        } else {
18039            self.refresh_inline_diagnostics(false, window, cx);
18040        }
18041
18042        cx.notify();
18043    }
18044
18045    pub fn toggle_minimap(
18046        &mut self,
18047        _: &ToggleMinimap,
18048        window: &mut Window,
18049        cx: &mut Context<Editor>,
18050    ) {
18051        if self.supports_minimap(cx) {
18052            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
18053        }
18054    }
18055
18056    fn refresh_inline_diagnostics(
18057        &mut self,
18058        debounce: bool,
18059        window: &mut Window,
18060        cx: &mut Context<Self>,
18061    ) {
18062        let max_severity = ProjectSettings::get_global(cx)
18063            .diagnostics
18064            .inline
18065            .max_severity
18066            .unwrap_or(self.diagnostics_max_severity);
18067
18068        if !self.inline_diagnostics_enabled()
18069            || !self.diagnostics_enabled()
18070            || !self.show_inline_diagnostics
18071            || max_severity == DiagnosticSeverity::Off
18072        {
18073            self.inline_diagnostics_update = Task::ready(());
18074            self.inline_diagnostics.clear();
18075            return;
18076        }
18077
18078        let debounce_ms = ProjectSettings::get_global(cx)
18079            .diagnostics
18080            .inline
18081            .update_debounce_ms;
18082        let debounce = if debounce && debounce_ms > 0 {
18083            Some(Duration::from_millis(debounce_ms))
18084        } else {
18085            None
18086        };
18087        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
18088            if let Some(debounce) = debounce {
18089                cx.background_executor().timer(debounce).await;
18090            }
18091            let Some(snapshot) = editor.upgrade().and_then(|editor| {
18092                editor
18093                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
18094                    .ok()
18095            }) else {
18096                return;
18097            };
18098
18099            let new_inline_diagnostics = cx
18100                .background_spawn(async move {
18101                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
18102                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
18103                        let message = diagnostic_entry
18104                            .diagnostic
18105                            .message
18106                            .split_once('\n')
18107                            .map(|(line, _)| line)
18108                            .map(SharedString::new)
18109                            .unwrap_or_else(|| {
18110                                SharedString::new(&*diagnostic_entry.diagnostic.message)
18111                            });
18112                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
18113                        let (Ok(i) | Err(i)) = inline_diagnostics
18114                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
18115                        inline_diagnostics.insert(
18116                            i,
18117                            (
18118                                start_anchor,
18119                                InlineDiagnostic {
18120                                    message,
18121                                    group_id: diagnostic_entry.diagnostic.group_id,
18122                                    start: diagnostic_entry.range.start.to_point(&snapshot),
18123                                    is_primary: diagnostic_entry.diagnostic.is_primary,
18124                                    severity: diagnostic_entry.diagnostic.severity,
18125                                },
18126                            ),
18127                        );
18128                    }
18129                    inline_diagnostics
18130                })
18131                .await;
18132
18133            editor
18134                .update(cx, |editor, cx| {
18135                    editor.inline_diagnostics = new_inline_diagnostics;
18136                    cx.notify();
18137                })
18138                .ok();
18139        });
18140    }
18141
18142    fn pull_diagnostics(
18143        &mut self,
18144        buffer_id: Option<BufferId>,
18145        window: &Window,
18146        cx: &mut Context<Self>,
18147    ) -> Option<()> {
18148        if self.ignore_lsp_data() || !self.diagnostics_enabled() {
18149            return None;
18150        }
18151        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
18152            .diagnostics
18153            .lsp_pull_diagnostics;
18154        if !pull_diagnostics_settings.enabled {
18155            return None;
18156        }
18157        let project = self.project()?.downgrade();
18158        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
18159        let mut buffers = self.buffer.read(cx).all_buffers();
18160        buffers.retain(|buffer| {
18161            let buffer_id_to_retain = buffer.read(cx).remote_id();
18162            buffer_id.is_none_or(|buffer_id| buffer_id == buffer_id_to_retain)
18163                && self.registered_buffers.contains_key(&buffer_id_to_retain)
18164        });
18165        if buffers.is_empty() {
18166            self.pull_diagnostics_task = Task::ready(());
18167            return None;
18168        }
18169
18170        self.pull_diagnostics_task = cx.spawn_in(window, async move |editor, cx| {
18171            cx.background_executor().timer(debounce).await;
18172
18173            let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
18174                buffers
18175                    .into_iter()
18176                    .filter_map(|buffer| {
18177                        project
18178                            .update(cx, |project, cx| {
18179                                project.lsp_store().update(cx, |lsp_store, cx| {
18180                                    lsp_store.pull_diagnostics_for_buffer(buffer, cx)
18181                                })
18182                            })
18183                            .ok()
18184                    })
18185                    .collect::<FuturesUnordered<_>>()
18186            }) else {
18187                return;
18188            };
18189
18190            while let Some(pull_task) = pull_diagnostics_tasks.next().await {
18191                match pull_task {
18192                    Ok(()) => {
18193                        if editor
18194                            .update_in(cx, |editor, window, cx| {
18195                                editor.update_diagnostics_state(window, cx);
18196                            })
18197                            .is_err()
18198                        {
18199                            return;
18200                        }
18201                    }
18202                    Err(e) => log::error!("Failed to update project diagnostics: {e:#}"),
18203                }
18204            }
18205        });
18206
18207        Some(())
18208    }
18209
18210    pub fn set_selections_from_remote(
18211        &mut self,
18212        selections: Vec<Selection<Anchor>>,
18213        pending_selection: Option<Selection<Anchor>>,
18214        window: &mut Window,
18215        cx: &mut Context<Self>,
18216    ) {
18217        let old_cursor_position = self.selections.newest_anchor().head();
18218        self.selections
18219            .change_with(&self.display_snapshot(cx), |s| {
18220                s.select_anchors(selections);
18221                if let Some(pending_selection) = pending_selection {
18222                    s.set_pending(pending_selection, SelectMode::Character);
18223                } else {
18224                    s.clear_pending();
18225                }
18226            });
18227        self.selections_did_change(
18228            false,
18229            &old_cursor_position,
18230            SelectionEffects::default(),
18231            window,
18232            cx,
18233        );
18234    }
18235
18236    pub fn transact(
18237        &mut self,
18238        window: &mut Window,
18239        cx: &mut Context<Self>,
18240        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
18241    ) -> Option<TransactionId> {
18242        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
18243            this.start_transaction_at(Instant::now(), window, cx);
18244            update(this, window, cx);
18245            this.end_transaction_at(Instant::now(), cx)
18246        })
18247    }
18248
18249    pub fn start_transaction_at(
18250        &mut self,
18251        now: Instant,
18252        window: &mut Window,
18253        cx: &mut Context<Self>,
18254    ) -> Option<TransactionId> {
18255        self.end_selection(window, cx);
18256        if let Some(tx_id) = self
18257            .buffer
18258            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
18259        {
18260            self.selection_history
18261                .insert_transaction(tx_id, self.selections.disjoint_anchors_arc());
18262            cx.emit(EditorEvent::TransactionBegun {
18263                transaction_id: tx_id,
18264            });
18265            Some(tx_id)
18266        } else {
18267            None
18268        }
18269    }
18270
18271    pub fn end_transaction_at(
18272        &mut self,
18273        now: Instant,
18274        cx: &mut Context<Self>,
18275    ) -> Option<TransactionId> {
18276        if let Some(transaction_id) = self
18277            .buffer
18278            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
18279        {
18280            if let Some((_, end_selections)) =
18281                self.selection_history.transaction_mut(transaction_id)
18282            {
18283                *end_selections = Some(self.selections.disjoint_anchors_arc());
18284            } else {
18285                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
18286            }
18287
18288            cx.emit(EditorEvent::Edited { transaction_id });
18289            Some(transaction_id)
18290        } else {
18291            None
18292        }
18293    }
18294
18295    pub fn modify_transaction_selection_history(
18296        &mut self,
18297        transaction_id: TransactionId,
18298        modify: impl FnOnce(&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)),
18299    ) -> bool {
18300        self.selection_history
18301            .transaction_mut(transaction_id)
18302            .map(modify)
18303            .is_some()
18304    }
18305
18306    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
18307        if self.selection_mark_mode {
18308            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
18309                s.move_with(|_, sel| {
18310                    sel.collapse_to(sel.head(), SelectionGoal::None);
18311                });
18312            })
18313        }
18314        self.selection_mark_mode = true;
18315        cx.notify();
18316    }
18317
18318    pub fn swap_selection_ends(
18319        &mut self,
18320        _: &actions::SwapSelectionEnds,
18321        window: &mut Window,
18322        cx: &mut Context<Self>,
18323    ) {
18324        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
18325            s.move_with(|_, sel| {
18326                if sel.start != sel.end {
18327                    sel.reversed = !sel.reversed
18328                }
18329            });
18330        });
18331        self.request_autoscroll(Autoscroll::newest(), cx);
18332        cx.notify();
18333    }
18334
18335    pub fn toggle_focus(
18336        workspace: &mut Workspace,
18337        _: &actions::ToggleFocus,
18338        window: &mut Window,
18339        cx: &mut Context<Workspace>,
18340    ) {
18341        let Some(item) = workspace.recent_active_item_by_type::<Self>(cx) else {
18342            return;
18343        };
18344        workspace.activate_item(&item, true, true, window, cx);
18345    }
18346
18347    pub fn toggle_fold(
18348        &mut self,
18349        _: &actions::ToggleFold,
18350        window: &mut Window,
18351        cx: &mut Context<Self>,
18352    ) {
18353        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18354            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18355            let selection = self.selections.newest::<Point>(&display_map);
18356
18357            let range = if selection.is_empty() {
18358                let point = selection.head().to_display_point(&display_map);
18359                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
18360                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
18361                    .to_point(&display_map);
18362                start..end
18363            } else {
18364                selection.range()
18365            };
18366            if display_map.folds_in_range(range).next().is_some() {
18367                self.unfold_lines(&Default::default(), window, cx)
18368            } else {
18369                self.fold(&Default::default(), window, cx)
18370            }
18371        } else {
18372            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18373            let buffer_ids: HashSet<_> = self
18374                .selections
18375                .disjoint_anchor_ranges()
18376                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18377                .collect();
18378
18379            let should_unfold = buffer_ids
18380                .iter()
18381                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
18382
18383            for buffer_id in buffer_ids {
18384                if should_unfold {
18385                    self.unfold_buffer(buffer_id, cx);
18386                } else {
18387                    self.fold_buffer(buffer_id, cx);
18388                }
18389            }
18390        }
18391    }
18392
18393    pub fn toggle_fold_recursive(
18394        &mut self,
18395        _: &actions::ToggleFoldRecursive,
18396        window: &mut Window,
18397        cx: &mut Context<Self>,
18398    ) {
18399        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
18400
18401        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18402        let range = if selection.is_empty() {
18403            let point = selection.head().to_display_point(&display_map);
18404            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
18405            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
18406                .to_point(&display_map);
18407            start..end
18408        } else {
18409            selection.range()
18410        };
18411        if display_map.folds_in_range(range).next().is_some() {
18412            self.unfold_recursive(&Default::default(), window, cx)
18413        } else {
18414            self.fold_recursive(&Default::default(), window, cx)
18415        }
18416    }
18417
18418    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
18419        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18420            let mut to_fold = Vec::new();
18421            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18422            let selections = self.selections.all_adjusted(&display_map);
18423
18424            for selection in selections {
18425                let range = selection.range().sorted();
18426                let buffer_start_row = range.start.row;
18427
18428                if range.start.row != range.end.row {
18429                    let mut found = false;
18430                    let mut row = range.start.row;
18431                    while row <= range.end.row {
18432                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
18433                        {
18434                            found = true;
18435                            row = crease.range().end.row + 1;
18436                            to_fold.push(crease);
18437                        } else {
18438                            row += 1
18439                        }
18440                    }
18441                    if found {
18442                        continue;
18443                    }
18444                }
18445
18446                for row in (0..=range.start.row).rev() {
18447                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
18448                        && crease.range().end.row >= buffer_start_row
18449                    {
18450                        to_fold.push(crease);
18451                        if row <= range.start.row {
18452                            break;
18453                        }
18454                    }
18455                }
18456            }
18457
18458            self.fold_creases(to_fold, true, window, cx);
18459        } else {
18460            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18461            let buffer_ids = self
18462                .selections
18463                .disjoint_anchor_ranges()
18464                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18465                .collect::<HashSet<_>>();
18466            for buffer_id in buffer_ids {
18467                self.fold_buffer(buffer_id, cx);
18468            }
18469        }
18470    }
18471
18472    pub fn toggle_fold_all(
18473        &mut self,
18474        _: &actions::ToggleFoldAll,
18475        window: &mut Window,
18476        cx: &mut Context<Self>,
18477    ) {
18478        if self.buffer.read(cx).is_singleton() {
18479            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18480            let has_folds = display_map
18481                .folds_in_range(0..display_map.buffer_snapshot().len())
18482                .next()
18483                .is_some();
18484
18485            if has_folds {
18486                self.unfold_all(&actions::UnfoldAll, window, cx);
18487            } else {
18488                self.fold_all(&actions::FoldAll, window, cx);
18489            }
18490        } else {
18491            let buffer_ids = self.buffer.read(cx).excerpt_buffer_ids();
18492            let should_unfold = buffer_ids
18493                .iter()
18494                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
18495
18496            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
18497                editor
18498                    .update_in(cx, |editor, _, cx| {
18499                        for buffer_id in buffer_ids {
18500                            if should_unfold {
18501                                editor.unfold_buffer(buffer_id, cx);
18502                            } else {
18503                                editor.fold_buffer(buffer_id, cx);
18504                            }
18505                        }
18506                    })
18507                    .ok();
18508            });
18509        }
18510    }
18511
18512    fn fold_at_level(
18513        &mut self,
18514        fold_at: &FoldAtLevel,
18515        window: &mut Window,
18516        cx: &mut Context<Self>,
18517    ) {
18518        if !self.buffer.read(cx).is_singleton() {
18519            return;
18520        }
18521
18522        let fold_at_level = fold_at.0;
18523        let snapshot = self.buffer.read(cx).snapshot(cx);
18524        let mut to_fold = Vec::new();
18525        let mut stack = vec![(0, snapshot.max_row().0, 1)];
18526
18527        let row_ranges_to_keep: Vec<Range<u32>> = self
18528            .selections
18529            .all::<Point>(&self.display_snapshot(cx))
18530            .into_iter()
18531            .map(|sel| sel.start.row..sel.end.row)
18532            .collect();
18533
18534        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
18535            while start_row < end_row {
18536                match self
18537                    .snapshot(window, cx)
18538                    .crease_for_buffer_row(MultiBufferRow(start_row))
18539                {
18540                    Some(crease) => {
18541                        let nested_start_row = crease.range().start.row + 1;
18542                        let nested_end_row = crease.range().end.row;
18543
18544                        if current_level < fold_at_level {
18545                            stack.push((nested_start_row, nested_end_row, current_level + 1));
18546                        } else if current_level == fold_at_level {
18547                            // Fold iff there is no selection completely contained within the fold region
18548                            if !row_ranges_to_keep.iter().any(|selection| {
18549                                selection.end >= nested_start_row
18550                                    && selection.start <= nested_end_row
18551                            }) {
18552                                to_fold.push(crease);
18553                            }
18554                        }
18555
18556                        start_row = nested_end_row + 1;
18557                    }
18558                    None => start_row += 1,
18559                }
18560            }
18561        }
18562
18563        self.fold_creases(to_fold, true, window, cx);
18564    }
18565
18566    pub fn fold_at_level_1(
18567        &mut self,
18568        _: &actions::FoldAtLevel1,
18569        window: &mut Window,
18570        cx: &mut Context<Self>,
18571    ) {
18572        self.fold_at_level(&actions::FoldAtLevel(1), window, cx);
18573    }
18574
18575    pub fn fold_at_level_2(
18576        &mut self,
18577        _: &actions::FoldAtLevel2,
18578        window: &mut Window,
18579        cx: &mut Context<Self>,
18580    ) {
18581        self.fold_at_level(&actions::FoldAtLevel(2), window, cx);
18582    }
18583
18584    pub fn fold_at_level_3(
18585        &mut self,
18586        _: &actions::FoldAtLevel3,
18587        window: &mut Window,
18588        cx: &mut Context<Self>,
18589    ) {
18590        self.fold_at_level(&actions::FoldAtLevel(3), window, cx);
18591    }
18592
18593    pub fn fold_at_level_4(
18594        &mut self,
18595        _: &actions::FoldAtLevel4,
18596        window: &mut Window,
18597        cx: &mut Context<Self>,
18598    ) {
18599        self.fold_at_level(&actions::FoldAtLevel(4), window, cx);
18600    }
18601
18602    pub fn fold_at_level_5(
18603        &mut self,
18604        _: &actions::FoldAtLevel5,
18605        window: &mut Window,
18606        cx: &mut Context<Self>,
18607    ) {
18608        self.fold_at_level(&actions::FoldAtLevel(5), window, cx);
18609    }
18610
18611    pub fn fold_at_level_6(
18612        &mut self,
18613        _: &actions::FoldAtLevel6,
18614        window: &mut Window,
18615        cx: &mut Context<Self>,
18616    ) {
18617        self.fold_at_level(&actions::FoldAtLevel(6), window, cx);
18618    }
18619
18620    pub fn fold_at_level_7(
18621        &mut self,
18622        _: &actions::FoldAtLevel7,
18623        window: &mut Window,
18624        cx: &mut Context<Self>,
18625    ) {
18626        self.fold_at_level(&actions::FoldAtLevel(7), window, cx);
18627    }
18628
18629    pub fn fold_at_level_8(
18630        &mut self,
18631        _: &actions::FoldAtLevel8,
18632        window: &mut Window,
18633        cx: &mut Context<Self>,
18634    ) {
18635        self.fold_at_level(&actions::FoldAtLevel(8), window, cx);
18636    }
18637
18638    pub fn fold_at_level_9(
18639        &mut self,
18640        _: &actions::FoldAtLevel9,
18641        window: &mut Window,
18642        cx: &mut Context<Self>,
18643    ) {
18644        self.fold_at_level(&actions::FoldAtLevel(9), window, cx);
18645    }
18646
18647    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
18648        if self.buffer.read(cx).is_singleton() {
18649            let mut fold_ranges = Vec::new();
18650            let snapshot = self.buffer.read(cx).snapshot(cx);
18651
18652            for row in 0..snapshot.max_row().0 {
18653                if let Some(foldable_range) = self
18654                    .snapshot(window, cx)
18655                    .crease_for_buffer_row(MultiBufferRow(row))
18656                {
18657                    fold_ranges.push(foldable_range);
18658                }
18659            }
18660
18661            self.fold_creases(fold_ranges, true, window, cx);
18662        } else {
18663            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
18664                editor
18665                    .update_in(cx, |editor, _, cx| {
18666                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
18667                            editor.fold_buffer(buffer_id, cx);
18668                        }
18669                    })
18670                    .ok();
18671            });
18672        }
18673    }
18674
18675    pub fn fold_function_bodies(
18676        &mut self,
18677        _: &actions::FoldFunctionBodies,
18678        window: &mut Window,
18679        cx: &mut Context<Self>,
18680    ) {
18681        let snapshot = self.buffer.read(cx).snapshot(cx);
18682
18683        let ranges = snapshot
18684            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
18685            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
18686            .collect::<Vec<_>>();
18687
18688        let creases = ranges
18689            .into_iter()
18690            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
18691            .collect();
18692
18693        self.fold_creases(creases, true, window, cx);
18694    }
18695
18696    pub fn fold_recursive(
18697        &mut self,
18698        _: &actions::FoldRecursive,
18699        window: &mut Window,
18700        cx: &mut Context<Self>,
18701    ) {
18702        let mut to_fold = Vec::new();
18703        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18704        let selections = self.selections.all_adjusted(&display_map);
18705
18706        for selection in selections {
18707            let range = selection.range().sorted();
18708            let buffer_start_row = range.start.row;
18709
18710            if range.start.row != range.end.row {
18711                let mut found = false;
18712                for row in range.start.row..=range.end.row {
18713                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
18714                        found = true;
18715                        to_fold.push(crease);
18716                    }
18717                }
18718                if found {
18719                    continue;
18720                }
18721            }
18722
18723            for row in (0..=range.start.row).rev() {
18724                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
18725                    if crease.range().end.row >= buffer_start_row {
18726                        to_fold.push(crease);
18727                    } else {
18728                        break;
18729                    }
18730                }
18731            }
18732        }
18733
18734        self.fold_creases(to_fold, true, window, cx);
18735    }
18736
18737    pub fn fold_at(
18738        &mut self,
18739        buffer_row: MultiBufferRow,
18740        window: &mut Window,
18741        cx: &mut Context<Self>,
18742    ) {
18743        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18744
18745        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
18746            let autoscroll = self
18747                .selections
18748                .all::<Point>(&display_map)
18749                .iter()
18750                .any(|selection| crease.range().overlaps(&selection.range()));
18751
18752            self.fold_creases(vec![crease], autoscroll, window, cx);
18753        }
18754    }
18755
18756    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
18757        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18758            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18759            let buffer = display_map.buffer_snapshot();
18760            let selections = self.selections.all::<Point>(&display_map);
18761            let ranges = selections
18762                .iter()
18763                .map(|s| {
18764                    let range = s.display_range(&display_map).sorted();
18765                    let mut start = range.start.to_point(&display_map);
18766                    let mut end = range.end.to_point(&display_map);
18767                    start.column = 0;
18768                    end.column = buffer.line_len(MultiBufferRow(end.row));
18769                    start..end
18770                })
18771                .collect::<Vec<_>>();
18772
18773            self.unfold_ranges(&ranges, true, true, cx);
18774        } else {
18775            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18776            let buffer_ids = self
18777                .selections
18778                .disjoint_anchor_ranges()
18779                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18780                .collect::<HashSet<_>>();
18781            for buffer_id in buffer_ids {
18782                self.unfold_buffer(buffer_id, cx);
18783            }
18784        }
18785    }
18786
18787    pub fn unfold_recursive(
18788        &mut self,
18789        _: &UnfoldRecursive,
18790        _window: &mut Window,
18791        cx: &mut Context<Self>,
18792    ) {
18793        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18794        let selections = self.selections.all::<Point>(&display_map);
18795        let ranges = selections
18796            .iter()
18797            .map(|s| {
18798                let mut range = s.display_range(&display_map).sorted();
18799                *range.start.column_mut() = 0;
18800                *range.end.column_mut() = display_map.line_len(range.end.row());
18801                let start = range.start.to_point(&display_map);
18802                let end = range.end.to_point(&display_map);
18803                start..end
18804            })
18805            .collect::<Vec<_>>();
18806
18807        self.unfold_ranges(&ranges, true, true, cx);
18808    }
18809
18810    pub fn unfold_at(
18811        &mut self,
18812        buffer_row: MultiBufferRow,
18813        _window: &mut Window,
18814        cx: &mut Context<Self>,
18815    ) {
18816        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18817
18818        let intersection_range = Point::new(buffer_row.0, 0)
18819            ..Point::new(
18820                buffer_row.0,
18821                display_map.buffer_snapshot().line_len(buffer_row),
18822            );
18823
18824        let autoscroll = self
18825            .selections
18826            .all::<Point>(&display_map)
18827            .iter()
18828            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
18829
18830        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
18831    }
18832
18833    pub fn unfold_all(
18834        &mut self,
18835        _: &actions::UnfoldAll,
18836        _window: &mut Window,
18837        cx: &mut Context<Self>,
18838    ) {
18839        if self.buffer.read(cx).is_singleton() {
18840            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18841            self.unfold_ranges(&[0..display_map.buffer_snapshot().len()], true, true, cx);
18842        } else {
18843            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
18844                editor
18845                    .update(cx, |editor, cx| {
18846                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
18847                            editor.unfold_buffer(buffer_id, cx);
18848                        }
18849                    })
18850                    .ok();
18851            });
18852        }
18853    }
18854
18855    pub fn fold_selected_ranges(
18856        &mut self,
18857        _: &FoldSelectedRanges,
18858        window: &mut Window,
18859        cx: &mut Context<Self>,
18860    ) {
18861        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18862        let selections = self.selections.all_adjusted(&display_map);
18863        let ranges = selections
18864            .into_iter()
18865            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
18866            .collect::<Vec<_>>();
18867        self.fold_creases(ranges, true, window, cx);
18868    }
18869
18870    pub fn fold_ranges<T: ToOffset + Clone>(
18871        &mut self,
18872        ranges: Vec<Range<T>>,
18873        auto_scroll: bool,
18874        window: &mut Window,
18875        cx: &mut Context<Self>,
18876    ) {
18877        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18878        let ranges = ranges
18879            .into_iter()
18880            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
18881            .collect::<Vec<_>>();
18882        self.fold_creases(ranges, auto_scroll, window, cx);
18883    }
18884
18885    pub fn fold_creases<T: ToOffset + Clone>(
18886        &mut self,
18887        creases: Vec<Crease<T>>,
18888        auto_scroll: bool,
18889        _window: &mut Window,
18890        cx: &mut Context<Self>,
18891    ) {
18892        if creases.is_empty() {
18893            return;
18894        }
18895
18896        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
18897
18898        if auto_scroll {
18899            self.request_autoscroll(Autoscroll::fit(), cx);
18900        }
18901
18902        cx.notify();
18903
18904        self.scrollbar_marker_state.dirty = true;
18905        self.folds_did_change(cx);
18906    }
18907
18908    /// Removes any folds whose ranges intersect any of the given ranges.
18909    pub fn unfold_ranges<T: ToOffset + Clone>(
18910        &mut self,
18911        ranges: &[Range<T>],
18912        inclusive: bool,
18913        auto_scroll: bool,
18914        cx: &mut Context<Self>,
18915    ) {
18916        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
18917            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
18918        });
18919        self.folds_did_change(cx);
18920    }
18921
18922    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18923        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
18924            return;
18925        }
18926
18927        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
18928        self.display_map.update(cx, |display_map, cx| {
18929            display_map.fold_buffers([buffer_id], cx)
18930        });
18931
18932        let snapshot = self.display_snapshot(cx);
18933        self.selections.change_with(&snapshot, |selections| {
18934            selections.remove_selections_from_buffer(buffer_id);
18935        });
18936
18937        cx.emit(EditorEvent::BufferFoldToggled {
18938            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
18939            folded: true,
18940        });
18941        cx.notify();
18942    }
18943
18944    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18945        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
18946            return;
18947        }
18948        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
18949        self.display_map.update(cx, |display_map, cx| {
18950            display_map.unfold_buffers([buffer_id], cx);
18951        });
18952        cx.emit(EditorEvent::BufferFoldToggled {
18953            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
18954            folded: false,
18955        });
18956        cx.notify();
18957    }
18958
18959    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
18960        self.display_map.read(cx).is_buffer_folded(buffer)
18961    }
18962
18963    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
18964        self.display_map.read(cx).folded_buffers()
18965    }
18966
18967    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18968        self.display_map.update(cx, |display_map, cx| {
18969            display_map.disable_header_for_buffer(buffer_id, cx);
18970        });
18971        cx.notify();
18972    }
18973
18974    /// Removes any folds with the given ranges.
18975    pub fn remove_folds_with_type<T: ToOffset + Clone>(
18976        &mut self,
18977        ranges: &[Range<T>],
18978        type_id: TypeId,
18979        auto_scroll: bool,
18980        cx: &mut Context<Self>,
18981    ) {
18982        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
18983            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
18984        });
18985        self.folds_did_change(cx);
18986    }
18987
18988    fn remove_folds_with<T: ToOffset + Clone>(
18989        &mut self,
18990        ranges: &[Range<T>],
18991        auto_scroll: bool,
18992        cx: &mut Context<Self>,
18993        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
18994    ) {
18995        if ranges.is_empty() {
18996            return;
18997        }
18998
18999        let mut buffers_affected = HashSet::default();
19000        let multi_buffer = self.buffer().read(cx);
19001        for range in ranges {
19002            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
19003                buffers_affected.insert(buffer.read(cx).remote_id());
19004            };
19005        }
19006
19007        self.display_map.update(cx, update);
19008
19009        if auto_scroll {
19010            self.request_autoscroll(Autoscroll::fit(), cx);
19011        }
19012
19013        cx.notify();
19014        self.scrollbar_marker_state.dirty = true;
19015        self.active_indent_guides_state.dirty = true;
19016    }
19017
19018    pub fn update_renderer_widths(
19019        &mut self,
19020        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
19021        cx: &mut Context<Self>,
19022    ) -> bool {
19023        self.display_map
19024            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
19025    }
19026
19027    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
19028        self.display_map.read(cx).fold_placeholder.clone()
19029    }
19030
19031    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
19032        self.buffer.update(cx, |buffer, cx| {
19033            buffer.set_all_diff_hunks_expanded(cx);
19034        });
19035    }
19036
19037    pub fn expand_all_diff_hunks(
19038        &mut self,
19039        _: &ExpandAllDiffHunks,
19040        _window: &mut Window,
19041        cx: &mut Context<Self>,
19042    ) {
19043        self.buffer.update(cx, |buffer, cx| {
19044            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
19045        });
19046    }
19047
19048    pub fn collapse_all_diff_hunks(
19049        &mut self,
19050        _: &CollapseAllDiffHunks,
19051        _window: &mut Window,
19052        cx: &mut Context<Self>,
19053    ) {
19054        self.buffer.update(cx, |buffer, cx| {
19055            buffer.collapse_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
19056        });
19057    }
19058
19059    pub fn toggle_selected_diff_hunks(
19060        &mut self,
19061        _: &ToggleSelectedDiffHunks,
19062        _window: &mut Window,
19063        cx: &mut Context<Self>,
19064    ) {
19065        let ranges: Vec<_> = self
19066            .selections
19067            .disjoint_anchors()
19068            .iter()
19069            .map(|s| s.range())
19070            .collect();
19071        self.toggle_diff_hunks_in_ranges(ranges, cx);
19072    }
19073
19074    pub fn diff_hunks_in_ranges<'a>(
19075        &'a self,
19076        ranges: &'a [Range<Anchor>],
19077        buffer: &'a MultiBufferSnapshot,
19078    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
19079        ranges.iter().flat_map(move |range| {
19080            let end_excerpt_id = range.end.excerpt_id;
19081            let range = range.to_point(buffer);
19082            let mut peek_end = range.end;
19083            if range.end.row < buffer.max_row().0 {
19084                peek_end = Point::new(range.end.row + 1, 0);
19085            }
19086            buffer
19087                .diff_hunks_in_range(range.start..peek_end)
19088                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
19089        })
19090    }
19091
19092    pub fn has_stageable_diff_hunks_in_ranges(
19093        &self,
19094        ranges: &[Range<Anchor>],
19095        snapshot: &MultiBufferSnapshot,
19096    ) -> bool {
19097        let mut hunks = self.diff_hunks_in_ranges(ranges, snapshot);
19098        hunks.any(|hunk| hunk.status().has_secondary_hunk())
19099    }
19100
19101    pub fn toggle_staged_selected_diff_hunks(
19102        &mut self,
19103        _: &::git::ToggleStaged,
19104        _: &mut Window,
19105        cx: &mut Context<Self>,
19106    ) {
19107        let snapshot = self.buffer.read(cx).snapshot(cx);
19108        let ranges: Vec<_> = self
19109            .selections
19110            .disjoint_anchors()
19111            .iter()
19112            .map(|s| s.range())
19113            .collect();
19114        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
19115        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
19116    }
19117
19118    pub fn set_render_diff_hunk_controls(
19119        &mut self,
19120        render_diff_hunk_controls: RenderDiffHunkControlsFn,
19121        cx: &mut Context<Self>,
19122    ) {
19123        self.render_diff_hunk_controls = render_diff_hunk_controls;
19124        cx.notify();
19125    }
19126
19127    pub fn stage_and_next(
19128        &mut self,
19129        _: &::git::StageAndNext,
19130        window: &mut Window,
19131        cx: &mut Context<Self>,
19132    ) {
19133        self.do_stage_or_unstage_and_next(true, window, cx);
19134    }
19135
19136    pub fn unstage_and_next(
19137        &mut self,
19138        _: &::git::UnstageAndNext,
19139        window: &mut Window,
19140        cx: &mut Context<Self>,
19141    ) {
19142        self.do_stage_or_unstage_and_next(false, window, cx);
19143    }
19144
19145    pub fn stage_or_unstage_diff_hunks(
19146        &mut self,
19147        stage: bool,
19148        ranges: Vec<Range<Anchor>>,
19149        cx: &mut Context<Self>,
19150    ) {
19151        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
19152        cx.spawn(async move |this, cx| {
19153            task.await?;
19154            this.update(cx, |this, cx| {
19155                let snapshot = this.buffer.read(cx).snapshot(cx);
19156                let chunk_by = this
19157                    .diff_hunks_in_ranges(&ranges, &snapshot)
19158                    .chunk_by(|hunk| hunk.buffer_id);
19159                for (buffer_id, hunks) in &chunk_by {
19160                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
19161                }
19162            })
19163        })
19164        .detach_and_log_err(cx);
19165    }
19166
19167    fn save_buffers_for_ranges_if_needed(
19168        &mut self,
19169        ranges: &[Range<Anchor>],
19170        cx: &mut Context<Editor>,
19171    ) -> Task<Result<()>> {
19172        let multibuffer = self.buffer.read(cx);
19173        let snapshot = multibuffer.read(cx);
19174        let buffer_ids: HashSet<_> = ranges
19175            .iter()
19176            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
19177            .collect();
19178        drop(snapshot);
19179
19180        let mut buffers = HashSet::default();
19181        for buffer_id in buffer_ids {
19182            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
19183                let buffer = buffer_entity.read(cx);
19184                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
19185                {
19186                    buffers.insert(buffer_entity);
19187                }
19188            }
19189        }
19190
19191        if let Some(project) = &self.project {
19192            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
19193        } else {
19194            Task::ready(Ok(()))
19195        }
19196    }
19197
19198    fn do_stage_or_unstage_and_next(
19199        &mut self,
19200        stage: bool,
19201        window: &mut Window,
19202        cx: &mut Context<Self>,
19203    ) {
19204        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
19205
19206        if ranges.iter().any(|range| range.start != range.end) {
19207            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
19208            return;
19209        }
19210
19211        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
19212        let snapshot = self.snapshot(window, cx);
19213        let position = self
19214            .selections
19215            .newest::<Point>(&snapshot.display_snapshot)
19216            .head();
19217        let mut row = snapshot
19218            .buffer_snapshot()
19219            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
19220            .find(|hunk| hunk.row_range.start.0 > position.row)
19221            .map(|hunk| hunk.row_range.start);
19222
19223        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
19224        // Outside of the project diff editor, wrap around to the beginning.
19225        if !all_diff_hunks_expanded {
19226            row = row.or_else(|| {
19227                snapshot
19228                    .buffer_snapshot()
19229                    .diff_hunks_in_range(Point::zero()..position)
19230                    .find(|hunk| hunk.row_range.end.0 < position.row)
19231                    .map(|hunk| hunk.row_range.start)
19232            });
19233        }
19234
19235        if let Some(row) = row {
19236            let destination = Point::new(row.0, 0);
19237            let autoscroll = Autoscroll::center();
19238
19239            self.unfold_ranges(&[destination..destination], false, false, cx);
19240            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
19241                s.select_ranges([destination..destination]);
19242            });
19243        }
19244    }
19245
19246    fn do_stage_or_unstage(
19247        &self,
19248        stage: bool,
19249        buffer_id: BufferId,
19250        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
19251        cx: &mut App,
19252    ) -> Option<()> {
19253        let project = self.project()?;
19254        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
19255        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
19256        let buffer_snapshot = buffer.read(cx).snapshot();
19257        let file_exists = buffer_snapshot
19258            .file()
19259            .is_some_and(|file| file.disk_state().exists());
19260        diff.update(cx, |diff, cx| {
19261            diff.stage_or_unstage_hunks(
19262                stage,
19263                &hunks
19264                    .map(|hunk| buffer_diff::DiffHunk {
19265                        buffer_range: hunk.buffer_range,
19266                        diff_base_byte_range: hunk.diff_base_byte_range,
19267                        secondary_status: hunk.secondary_status,
19268                        range: Point::zero()..Point::zero(), // unused
19269                    })
19270                    .collect::<Vec<_>>(),
19271                &buffer_snapshot,
19272                file_exists,
19273                cx,
19274            )
19275        });
19276        None
19277    }
19278
19279    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
19280        let ranges: Vec<_> = self
19281            .selections
19282            .disjoint_anchors()
19283            .iter()
19284            .map(|s| s.range())
19285            .collect();
19286        self.buffer
19287            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
19288    }
19289
19290    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
19291        self.buffer.update(cx, |buffer, cx| {
19292            let ranges = vec![Anchor::min()..Anchor::max()];
19293            if !buffer.all_diff_hunks_expanded()
19294                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
19295            {
19296                buffer.collapse_diff_hunks(ranges, cx);
19297                true
19298            } else {
19299                false
19300            }
19301        })
19302    }
19303
19304    fn toggle_diff_hunks_in_ranges(
19305        &mut self,
19306        ranges: Vec<Range<Anchor>>,
19307        cx: &mut Context<Editor>,
19308    ) {
19309        self.buffer.update(cx, |buffer, cx| {
19310            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
19311            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
19312        })
19313    }
19314
19315    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
19316        self.buffer.update(cx, |buffer, cx| {
19317            let snapshot = buffer.snapshot(cx);
19318            let excerpt_id = range.end.excerpt_id;
19319            let point_range = range.to_point(&snapshot);
19320            let expand = !buffer.single_hunk_is_expanded(range, cx);
19321            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
19322        })
19323    }
19324
19325    pub(crate) fn apply_all_diff_hunks(
19326        &mut self,
19327        _: &ApplyAllDiffHunks,
19328        window: &mut Window,
19329        cx: &mut Context<Self>,
19330    ) {
19331        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19332
19333        let buffers = self.buffer.read(cx).all_buffers();
19334        for branch_buffer in buffers {
19335            branch_buffer.update(cx, |branch_buffer, cx| {
19336                branch_buffer.merge_into_base(Vec::new(), cx);
19337            });
19338        }
19339
19340        if let Some(project) = self.project.clone() {
19341            self.save(
19342                SaveOptions {
19343                    format: true,
19344                    autosave: false,
19345                },
19346                project,
19347                window,
19348                cx,
19349            )
19350            .detach_and_log_err(cx);
19351        }
19352    }
19353
19354    pub(crate) fn apply_selected_diff_hunks(
19355        &mut self,
19356        _: &ApplyDiffHunk,
19357        window: &mut Window,
19358        cx: &mut Context<Self>,
19359    ) {
19360        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19361        let snapshot = self.snapshot(window, cx);
19362        let hunks = snapshot.hunks_for_ranges(
19363            self.selections
19364                .all(&snapshot.display_snapshot)
19365                .into_iter()
19366                .map(|selection| selection.range()),
19367        );
19368        let mut ranges_by_buffer = HashMap::default();
19369        self.transact(window, cx, |editor, _window, cx| {
19370            for hunk in hunks {
19371                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
19372                    ranges_by_buffer
19373                        .entry(buffer.clone())
19374                        .or_insert_with(Vec::new)
19375                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
19376                }
19377            }
19378
19379            for (buffer, ranges) in ranges_by_buffer {
19380                buffer.update(cx, |buffer, cx| {
19381                    buffer.merge_into_base(ranges, cx);
19382                });
19383            }
19384        });
19385
19386        if let Some(project) = self.project.clone() {
19387            self.save(
19388                SaveOptions {
19389                    format: true,
19390                    autosave: false,
19391                },
19392                project,
19393                window,
19394                cx,
19395            )
19396            .detach_and_log_err(cx);
19397        }
19398    }
19399
19400    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
19401        if hovered != self.gutter_hovered {
19402            self.gutter_hovered = hovered;
19403            cx.notify();
19404        }
19405    }
19406
19407    pub fn insert_blocks(
19408        &mut self,
19409        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
19410        autoscroll: Option<Autoscroll>,
19411        cx: &mut Context<Self>,
19412    ) -> Vec<CustomBlockId> {
19413        let blocks = self
19414            .display_map
19415            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
19416        if let Some(autoscroll) = autoscroll {
19417            self.request_autoscroll(autoscroll, cx);
19418        }
19419        cx.notify();
19420        blocks
19421    }
19422
19423    pub fn resize_blocks(
19424        &mut self,
19425        heights: HashMap<CustomBlockId, u32>,
19426        autoscroll: Option<Autoscroll>,
19427        cx: &mut Context<Self>,
19428    ) {
19429        self.display_map
19430            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
19431        if let Some(autoscroll) = autoscroll {
19432            self.request_autoscroll(autoscroll, cx);
19433        }
19434        cx.notify();
19435    }
19436
19437    pub fn replace_blocks(
19438        &mut self,
19439        renderers: HashMap<CustomBlockId, RenderBlock>,
19440        autoscroll: Option<Autoscroll>,
19441        cx: &mut Context<Self>,
19442    ) {
19443        self.display_map
19444            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
19445        if let Some(autoscroll) = autoscroll {
19446            self.request_autoscroll(autoscroll, cx);
19447        }
19448        cx.notify();
19449    }
19450
19451    pub fn remove_blocks(
19452        &mut self,
19453        block_ids: HashSet<CustomBlockId>,
19454        autoscroll: Option<Autoscroll>,
19455        cx: &mut Context<Self>,
19456    ) {
19457        self.display_map.update(cx, |display_map, cx| {
19458            display_map.remove_blocks(block_ids, cx)
19459        });
19460        if let Some(autoscroll) = autoscroll {
19461            self.request_autoscroll(autoscroll, cx);
19462        }
19463        cx.notify();
19464    }
19465
19466    pub fn row_for_block(
19467        &self,
19468        block_id: CustomBlockId,
19469        cx: &mut Context<Self>,
19470    ) -> Option<DisplayRow> {
19471        self.display_map
19472            .update(cx, |map, cx| map.row_for_block(block_id, cx))
19473    }
19474
19475    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
19476        self.focused_block = Some(focused_block);
19477    }
19478
19479    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
19480        self.focused_block.take()
19481    }
19482
19483    pub fn insert_creases(
19484        &mut self,
19485        creases: impl IntoIterator<Item = Crease<Anchor>>,
19486        cx: &mut Context<Self>,
19487    ) -> Vec<CreaseId> {
19488        self.display_map
19489            .update(cx, |map, cx| map.insert_creases(creases, cx))
19490    }
19491
19492    pub fn remove_creases(
19493        &mut self,
19494        ids: impl IntoIterator<Item = CreaseId>,
19495        cx: &mut Context<Self>,
19496    ) -> Vec<(CreaseId, Range<Anchor>)> {
19497        self.display_map
19498            .update(cx, |map, cx| map.remove_creases(ids, cx))
19499    }
19500
19501    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
19502        self.display_map
19503            .update(cx, |map, cx| map.snapshot(cx))
19504            .longest_row()
19505    }
19506
19507    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
19508        self.display_map
19509            .update(cx, |map, cx| map.snapshot(cx))
19510            .max_point()
19511    }
19512
19513    pub fn text(&self, cx: &App) -> String {
19514        self.buffer.read(cx).read(cx).text()
19515    }
19516
19517    pub fn is_empty(&self, cx: &App) -> bool {
19518        self.buffer.read(cx).read(cx).is_empty()
19519    }
19520
19521    pub fn text_option(&self, cx: &App) -> Option<String> {
19522        let text = self.text(cx);
19523        let text = text.trim();
19524
19525        if text.is_empty() {
19526            return None;
19527        }
19528
19529        Some(text.to_string())
19530    }
19531
19532    pub fn set_text(
19533        &mut self,
19534        text: impl Into<Arc<str>>,
19535        window: &mut Window,
19536        cx: &mut Context<Self>,
19537    ) {
19538        self.transact(window, cx, |this, _, cx| {
19539            this.buffer
19540                .read(cx)
19541                .as_singleton()
19542                .expect("you can only call set_text on editors for singleton buffers")
19543                .update(cx, |buffer, cx| buffer.set_text(text, cx));
19544        });
19545    }
19546
19547    pub fn display_text(&self, cx: &mut App) -> String {
19548        self.display_map
19549            .update(cx, |map, cx| map.snapshot(cx))
19550            .text()
19551    }
19552
19553    fn create_minimap(
19554        &self,
19555        minimap_settings: MinimapSettings,
19556        window: &mut Window,
19557        cx: &mut Context<Self>,
19558    ) -> Option<Entity<Self>> {
19559        (minimap_settings.minimap_enabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton)
19560            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
19561    }
19562
19563    fn initialize_new_minimap(
19564        &self,
19565        minimap_settings: MinimapSettings,
19566        window: &mut Window,
19567        cx: &mut Context<Self>,
19568    ) -> Entity<Self> {
19569        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
19570
19571        let mut minimap = Editor::new_internal(
19572            EditorMode::Minimap {
19573                parent: cx.weak_entity(),
19574            },
19575            self.buffer.clone(),
19576            None,
19577            Some(self.display_map.clone()),
19578            window,
19579            cx,
19580        );
19581        minimap.scroll_manager.clone_state(&self.scroll_manager);
19582        minimap.set_text_style_refinement(TextStyleRefinement {
19583            font_size: Some(MINIMAP_FONT_SIZE),
19584            font_weight: Some(MINIMAP_FONT_WEIGHT),
19585            ..Default::default()
19586        });
19587        minimap.update_minimap_configuration(minimap_settings, cx);
19588        cx.new(|_| minimap)
19589    }
19590
19591    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
19592        let current_line_highlight = minimap_settings
19593            .current_line_highlight
19594            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
19595        self.set_current_line_highlight(Some(current_line_highlight));
19596    }
19597
19598    pub fn minimap(&self) -> Option<&Entity<Self>> {
19599        self.minimap
19600            .as_ref()
19601            .filter(|_| self.minimap_visibility.visible())
19602    }
19603
19604    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
19605        let mut wrap_guides = smallvec![];
19606
19607        if self.show_wrap_guides == Some(false) {
19608            return wrap_guides;
19609        }
19610
19611        let settings = self.buffer.read(cx).language_settings(cx);
19612        if settings.show_wrap_guides {
19613            match self.soft_wrap_mode(cx) {
19614                SoftWrap::Column(soft_wrap) => {
19615                    wrap_guides.push((soft_wrap as usize, true));
19616                }
19617                SoftWrap::Bounded(soft_wrap) => {
19618                    wrap_guides.push((soft_wrap as usize, true));
19619                }
19620                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
19621            }
19622            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
19623        }
19624
19625        wrap_guides
19626    }
19627
19628    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
19629        let settings = self.buffer.read(cx).language_settings(cx);
19630        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
19631        match mode {
19632            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
19633                SoftWrap::None
19634            }
19635            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
19636            language_settings::SoftWrap::PreferredLineLength => {
19637                SoftWrap::Column(settings.preferred_line_length)
19638            }
19639            language_settings::SoftWrap::Bounded => {
19640                SoftWrap::Bounded(settings.preferred_line_length)
19641            }
19642        }
19643    }
19644
19645    pub fn set_soft_wrap_mode(
19646        &mut self,
19647        mode: language_settings::SoftWrap,
19648
19649        cx: &mut Context<Self>,
19650    ) {
19651        self.soft_wrap_mode_override = Some(mode);
19652        cx.notify();
19653    }
19654
19655    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
19656        self.hard_wrap = hard_wrap;
19657        cx.notify();
19658    }
19659
19660    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
19661        self.text_style_refinement = Some(style);
19662    }
19663
19664    /// called by the Element so we know what style we were most recently rendered with.
19665    pub fn set_style(&mut self, style: EditorStyle, window: &mut Window, cx: &mut Context<Self>) {
19666        // We intentionally do not inform the display map about the minimap style
19667        // so that wrapping is not recalculated and stays consistent for the editor
19668        // and its linked minimap.
19669        if !self.mode.is_minimap() {
19670            let font = style.text.font();
19671            let font_size = style.text.font_size.to_pixels(window.rem_size());
19672            let display_map = self
19673                .placeholder_display_map
19674                .as_ref()
19675                .filter(|_| self.is_empty(cx))
19676                .unwrap_or(&self.display_map);
19677
19678            display_map.update(cx, |map, cx| map.set_font(font, font_size, cx));
19679        }
19680        self.style = Some(style);
19681    }
19682
19683    pub fn style(&self) -> Option<&EditorStyle> {
19684        self.style.as_ref()
19685    }
19686
19687    // Called by the element. This method is not designed to be called outside of the editor
19688    // element's layout code because it does not notify when rewrapping is computed synchronously.
19689    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
19690        if self.is_empty(cx) {
19691            self.placeholder_display_map
19692                .as_ref()
19693                .map_or(false, |display_map| {
19694                    display_map.update(cx, |map, cx| map.set_wrap_width(width, cx))
19695                })
19696        } else {
19697            self.display_map
19698                .update(cx, |map, cx| map.set_wrap_width(width, cx))
19699        }
19700    }
19701
19702    pub fn set_soft_wrap(&mut self) {
19703        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
19704    }
19705
19706    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
19707        if self.soft_wrap_mode_override.is_some() {
19708            self.soft_wrap_mode_override.take();
19709        } else {
19710            let soft_wrap = match self.soft_wrap_mode(cx) {
19711                SoftWrap::GitDiff => return,
19712                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
19713                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
19714                    language_settings::SoftWrap::None
19715                }
19716            };
19717            self.soft_wrap_mode_override = Some(soft_wrap);
19718        }
19719        cx.notify();
19720    }
19721
19722    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
19723        let Some(workspace) = self.workspace() else {
19724            return;
19725        };
19726        let fs = workspace.read(cx).app_state().fs.clone();
19727        let current_show = TabBarSettings::get_global(cx).show;
19728        update_settings_file(fs, cx, move |setting, _| {
19729            setting.tab_bar.get_or_insert_default().show = Some(!current_show);
19730        });
19731    }
19732
19733    pub fn toggle_indent_guides(
19734        &mut self,
19735        _: &ToggleIndentGuides,
19736        _: &mut Window,
19737        cx: &mut Context<Self>,
19738    ) {
19739        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
19740            self.buffer
19741                .read(cx)
19742                .language_settings(cx)
19743                .indent_guides
19744                .enabled
19745        });
19746        self.show_indent_guides = Some(!currently_enabled);
19747        cx.notify();
19748    }
19749
19750    fn should_show_indent_guides(&self) -> Option<bool> {
19751        self.show_indent_guides
19752    }
19753
19754    pub fn toggle_line_numbers(
19755        &mut self,
19756        _: &ToggleLineNumbers,
19757        _: &mut Window,
19758        cx: &mut Context<Self>,
19759    ) {
19760        let mut editor_settings = EditorSettings::get_global(cx).clone();
19761        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
19762        EditorSettings::override_global(editor_settings, cx);
19763    }
19764
19765    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
19766        if let Some(show_line_numbers) = self.show_line_numbers {
19767            return show_line_numbers;
19768        }
19769        EditorSettings::get_global(cx).gutter.line_numbers
19770    }
19771
19772    pub fn relative_line_numbers(&self, cx: &mut App) -> RelativeLineNumbers {
19773        match (
19774            self.use_relative_line_numbers,
19775            EditorSettings::get_global(cx).relative_line_numbers,
19776        ) {
19777            (None, setting) => setting,
19778            (Some(false), _) => RelativeLineNumbers::Disabled,
19779            (Some(true), RelativeLineNumbers::Wrapped) => RelativeLineNumbers::Wrapped,
19780            (Some(true), _) => RelativeLineNumbers::Enabled,
19781        }
19782    }
19783
19784    pub fn toggle_relative_line_numbers(
19785        &mut self,
19786        _: &ToggleRelativeLineNumbers,
19787        _: &mut Window,
19788        cx: &mut Context<Self>,
19789    ) {
19790        let is_relative = self.relative_line_numbers(cx);
19791        self.set_relative_line_number(Some(!is_relative.enabled()), cx)
19792    }
19793
19794    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
19795        self.use_relative_line_numbers = is_relative;
19796        cx.notify();
19797    }
19798
19799    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
19800        self.show_gutter = show_gutter;
19801        cx.notify();
19802    }
19803
19804    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
19805        self.show_scrollbars = ScrollbarAxes {
19806            horizontal: show,
19807            vertical: show,
19808        };
19809        cx.notify();
19810    }
19811
19812    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
19813        self.show_scrollbars.vertical = show;
19814        cx.notify();
19815    }
19816
19817    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
19818        self.show_scrollbars.horizontal = show;
19819        cx.notify();
19820    }
19821
19822    pub fn set_minimap_visibility(
19823        &mut self,
19824        minimap_visibility: MinimapVisibility,
19825        window: &mut Window,
19826        cx: &mut Context<Self>,
19827    ) {
19828        if self.minimap_visibility != minimap_visibility {
19829            if minimap_visibility.visible() && self.minimap.is_none() {
19830                let minimap_settings = EditorSettings::get_global(cx).minimap;
19831                self.minimap =
19832                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
19833            }
19834            self.minimap_visibility = minimap_visibility;
19835            cx.notify();
19836        }
19837    }
19838
19839    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19840        self.set_show_scrollbars(false, cx);
19841        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
19842    }
19843
19844    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19845        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
19846    }
19847
19848    /// Normally the text in full mode and auto height editors is padded on the
19849    /// left side by roughly half a character width for improved hit testing.
19850    ///
19851    /// Use this method to disable this for cases where this is not wanted (e.g.
19852    /// if you want to align the editor text with some other text above or below)
19853    /// or if you want to add this padding to single-line editors.
19854    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
19855        self.offset_content = offset_content;
19856        cx.notify();
19857    }
19858
19859    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
19860        self.show_line_numbers = Some(show_line_numbers);
19861        cx.notify();
19862    }
19863
19864    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
19865        self.disable_expand_excerpt_buttons = true;
19866        cx.notify();
19867    }
19868
19869    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
19870        self.show_git_diff_gutter = Some(show_git_diff_gutter);
19871        cx.notify();
19872    }
19873
19874    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
19875        self.show_code_actions = Some(show_code_actions);
19876        cx.notify();
19877    }
19878
19879    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
19880        self.show_runnables = Some(show_runnables);
19881        cx.notify();
19882    }
19883
19884    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
19885        self.show_breakpoints = Some(show_breakpoints);
19886        cx.notify();
19887    }
19888
19889    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
19890        if self.display_map.read(cx).masked != masked {
19891            self.display_map.update(cx, |map, _| map.masked = masked);
19892        }
19893        cx.notify()
19894    }
19895
19896    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
19897        self.show_wrap_guides = Some(show_wrap_guides);
19898        cx.notify();
19899    }
19900
19901    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
19902        self.show_indent_guides = Some(show_indent_guides);
19903        cx.notify();
19904    }
19905
19906    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
19907        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
19908            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local())
19909                && let Some(dir) = file.abs_path(cx).parent()
19910            {
19911                return Some(dir.to_owned());
19912            }
19913        }
19914
19915        None
19916    }
19917
19918    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
19919        self.active_excerpt(cx)?
19920            .1
19921            .read(cx)
19922            .file()
19923            .and_then(|f| f.as_local())
19924    }
19925
19926    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
19927        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
19928            let buffer = buffer.read(cx);
19929            if let Some(project_path) = buffer.project_path(cx) {
19930                let project = self.project()?.read(cx);
19931                project.absolute_path(&project_path, cx)
19932            } else {
19933                buffer
19934                    .file()
19935                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
19936            }
19937        })
19938    }
19939
19940    pub fn reveal_in_finder(
19941        &mut self,
19942        _: &RevealInFileManager,
19943        _window: &mut Window,
19944        cx: &mut Context<Self>,
19945    ) {
19946        if let Some(target) = self.target_file(cx) {
19947            cx.reveal_path(&target.abs_path(cx));
19948        }
19949    }
19950
19951    pub fn copy_path(
19952        &mut self,
19953        _: &zed_actions::workspace::CopyPath,
19954        _window: &mut Window,
19955        cx: &mut Context<Self>,
19956    ) {
19957        if let Some(path) = self.target_file_abs_path(cx)
19958            && let Some(path) = path.to_str()
19959        {
19960            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
19961        } else {
19962            cx.propagate();
19963        }
19964    }
19965
19966    pub fn copy_relative_path(
19967        &mut self,
19968        _: &zed_actions::workspace::CopyRelativePath,
19969        _window: &mut Window,
19970        cx: &mut Context<Self>,
19971    ) {
19972        if let Some(path) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
19973            let project = self.project()?.read(cx);
19974            let path = buffer.read(cx).file()?.path();
19975            let path = path.display(project.path_style(cx));
19976            Some(path)
19977        }) {
19978            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
19979        } else {
19980            cx.propagate();
19981        }
19982    }
19983
19984    /// Returns the project path for the editor's buffer, if any buffer is
19985    /// opened in the editor.
19986    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
19987        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
19988            buffer.read(cx).project_path(cx)
19989        } else {
19990            None
19991        }
19992    }
19993
19994    // Returns true if the editor handled a go-to-line request
19995    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
19996        maybe!({
19997            let breakpoint_store = self.breakpoint_store.as_ref()?;
19998
19999            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
20000            else {
20001                self.clear_row_highlights::<ActiveDebugLine>();
20002                return None;
20003            };
20004
20005            let position = active_stack_frame.position;
20006            let buffer_id = position.buffer_id?;
20007            let snapshot = self
20008                .project
20009                .as_ref()?
20010                .read(cx)
20011                .buffer_for_id(buffer_id, cx)?
20012                .read(cx)
20013                .snapshot();
20014
20015            let mut handled = false;
20016            for (id, ExcerptRange { context, .. }) in
20017                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
20018            {
20019                if context.start.cmp(&position, &snapshot).is_ge()
20020                    || context.end.cmp(&position, &snapshot).is_lt()
20021                {
20022                    continue;
20023                }
20024                let snapshot = self.buffer.read(cx).snapshot(cx);
20025                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
20026
20027                handled = true;
20028                self.clear_row_highlights::<ActiveDebugLine>();
20029
20030                self.go_to_line::<ActiveDebugLine>(
20031                    multibuffer_anchor,
20032                    Some(cx.theme().colors().editor_debugger_active_line_background),
20033                    window,
20034                    cx,
20035                );
20036
20037                cx.notify();
20038            }
20039
20040            handled.then_some(())
20041        })
20042        .is_some()
20043    }
20044
20045    pub fn copy_file_name_without_extension(
20046        &mut self,
20047        _: &CopyFileNameWithoutExtension,
20048        _: &mut Window,
20049        cx: &mut Context<Self>,
20050    ) {
20051        if let Some(file) = self.target_file(cx)
20052            && let Some(file_stem) = file.path().file_stem()
20053        {
20054            cx.write_to_clipboard(ClipboardItem::new_string(file_stem.to_string()));
20055        }
20056    }
20057
20058    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
20059        if let Some(file) = self.target_file(cx)
20060            && let Some(name) = file.path().file_name()
20061        {
20062            cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
20063        }
20064    }
20065
20066    pub fn toggle_git_blame(
20067        &mut self,
20068        _: &::git::Blame,
20069        window: &mut Window,
20070        cx: &mut Context<Self>,
20071    ) {
20072        self.show_git_blame_gutter = !self.show_git_blame_gutter;
20073
20074        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
20075            self.start_git_blame(true, window, cx);
20076        }
20077
20078        cx.notify();
20079    }
20080
20081    pub fn toggle_git_blame_inline(
20082        &mut self,
20083        _: &ToggleGitBlameInline,
20084        window: &mut Window,
20085        cx: &mut Context<Self>,
20086    ) {
20087        self.toggle_git_blame_inline_internal(true, window, cx);
20088        cx.notify();
20089    }
20090
20091    pub fn open_git_blame_commit(
20092        &mut self,
20093        _: &OpenGitBlameCommit,
20094        window: &mut Window,
20095        cx: &mut Context<Self>,
20096    ) {
20097        self.open_git_blame_commit_internal(window, cx);
20098    }
20099
20100    fn open_git_blame_commit_internal(
20101        &mut self,
20102        window: &mut Window,
20103        cx: &mut Context<Self>,
20104    ) -> Option<()> {
20105        let blame = self.blame.as_ref()?;
20106        let snapshot = self.snapshot(window, cx);
20107        let cursor = self
20108            .selections
20109            .newest::<Point>(&snapshot.display_snapshot)
20110            .head();
20111        let (buffer, point, _) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)?;
20112        let (_, blame_entry) = blame
20113            .update(cx, |blame, cx| {
20114                blame
20115                    .blame_for_rows(
20116                        &[RowInfo {
20117                            buffer_id: Some(buffer.remote_id()),
20118                            buffer_row: Some(point.row),
20119                            ..Default::default()
20120                        }],
20121                        cx,
20122                    )
20123                    .next()
20124            })
20125            .flatten()?;
20126        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
20127        let repo = blame.read(cx).repository(cx, buffer.remote_id())?;
20128        let workspace = self.workspace()?.downgrade();
20129        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
20130        None
20131    }
20132
20133    pub fn git_blame_inline_enabled(&self) -> bool {
20134        self.git_blame_inline_enabled
20135    }
20136
20137    pub fn toggle_selection_menu(
20138        &mut self,
20139        _: &ToggleSelectionMenu,
20140        _: &mut Window,
20141        cx: &mut Context<Self>,
20142    ) {
20143        self.show_selection_menu = self
20144            .show_selection_menu
20145            .map(|show_selections_menu| !show_selections_menu)
20146            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
20147
20148        cx.notify();
20149    }
20150
20151    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
20152        self.show_selection_menu
20153            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
20154    }
20155
20156    fn start_git_blame(
20157        &mut self,
20158        user_triggered: bool,
20159        window: &mut Window,
20160        cx: &mut Context<Self>,
20161    ) {
20162        if let Some(project) = self.project() {
20163            if let Some(buffer) = self.buffer().read(cx).as_singleton()
20164                && buffer.read(cx).file().is_none()
20165            {
20166                return;
20167            }
20168
20169            let focused = self.focus_handle(cx).contains_focused(window, cx);
20170
20171            let project = project.clone();
20172            let blame = cx
20173                .new(|cx| GitBlame::new(self.buffer.clone(), project, user_triggered, focused, cx));
20174            self.blame_subscription =
20175                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
20176            self.blame = Some(blame);
20177        }
20178    }
20179
20180    fn toggle_git_blame_inline_internal(
20181        &mut self,
20182        user_triggered: bool,
20183        window: &mut Window,
20184        cx: &mut Context<Self>,
20185    ) {
20186        if self.git_blame_inline_enabled {
20187            self.git_blame_inline_enabled = false;
20188            self.show_git_blame_inline = false;
20189            self.show_git_blame_inline_delay_task.take();
20190        } else {
20191            self.git_blame_inline_enabled = true;
20192            self.start_git_blame_inline(user_triggered, window, cx);
20193        }
20194
20195        cx.notify();
20196    }
20197
20198    fn start_git_blame_inline(
20199        &mut self,
20200        user_triggered: bool,
20201        window: &mut Window,
20202        cx: &mut Context<Self>,
20203    ) {
20204        self.start_git_blame(user_triggered, window, cx);
20205
20206        if ProjectSettings::get_global(cx)
20207            .git
20208            .inline_blame_delay()
20209            .is_some()
20210        {
20211            self.start_inline_blame_timer(window, cx);
20212        } else {
20213            self.show_git_blame_inline = true
20214        }
20215    }
20216
20217    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
20218        self.blame.as_ref()
20219    }
20220
20221    pub fn show_git_blame_gutter(&self) -> bool {
20222        self.show_git_blame_gutter
20223    }
20224
20225    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
20226        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
20227    }
20228
20229    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
20230        self.show_git_blame_inline
20231            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
20232            && !self.newest_selection_head_on_empty_line(cx)
20233            && self.has_blame_entries(cx)
20234    }
20235
20236    fn has_blame_entries(&self, cx: &App) -> bool {
20237        self.blame()
20238            .is_some_and(|blame| blame.read(cx).has_generated_entries())
20239    }
20240
20241    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
20242        let cursor_anchor = self.selections.newest_anchor().head();
20243
20244        let snapshot = self.buffer.read(cx).snapshot(cx);
20245        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
20246
20247        snapshot.line_len(buffer_row) == 0
20248    }
20249
20250    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
20251        let buffer_and_selection = maybe!({
20252            let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
20253            let selection_range = selection.range();
20254
20255            let multi_buffer = self.buffer().read(cx);
20256            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
20257            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
20258
20259            let (buffer, range, _) = if selection.reversed {
20260                buffer_ranges.first()
20261            } else {
20262                buffer_ranges.last()
20263            }?;
20264
20265            let selection = text::ToPoint::to_point(&range.start, buffer).row
20266                ..text::ToPoint::to_point(&range.end, buffer).row;
20267            Some((multi_buffer.buffer(buffer.remote_id()).unwrap(), selection))
20268        });
20269
20270        let Some((buffer, selection)) = buffer_and_selection else {
20271            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
20272        };
20273
20274        let Some(project) = self.project() else {
20275            return Task::ready(Err(anyhow!("editor does not have project")));
20276        };
20277
20278        project.update(cx, |project, cx| {
20279            project.get_permalink_to_line(&buffer, selection, cx)
20280        })
20281    }
20282
20283    pub fn copy_permalink_to_line(
20284        &mut self,
20285        _: &CopyPermalinkToLine,
20286        window: &mut Window,
20287        cx: &mut Context<Self>,
20288    ) {
20289        let permalink_task = self.get_permalink_to_line(cx);
20290        let workspace = self.workspace();
20291
20292        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
20293            Ok(permalink) => {
20294                cx.update(|_, cx| {
20295                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
20296                })
20297                .ok();
20298            }
20299            Err(err) => {
20300                let message = format!("Failed to copy permalink: {err}");
20301
20302                anyhow::Result::<()>::Err(err).log_err();
20303
20304                if let Some(workspace) = workspace {
20305                    workspace
20306                        .update_in(cx, |workspace, _, cx| {
20307                            struct CopyPermalinkToLine;
20308
20309                            workspace.show_toast(
20310                                Toast::new(
20311                                    NotificationId::unique::<CopyPermalinkToLine>(),
20312                                    message,
20313                                ),
20314                                cx,
20315                            )
20316                        })
20317                        .ok();
20318                }
20319            }
20320        })
20321        .detach();
20322    }
20323
20324    pub fn copy_file_location(
20325        &mut self,
20326        _: &CopyFileLocation,
20327        _: &mut Window,
20328        cx: &mut Context<Self>,
20329    ) {
20330        let selection = self
20331            .selections
20332            .newest::<Point>(&self.display_snapshot(cx))
20333            .start
20334            .row
20335            + 1;
20336        if let Some(file) = self.target_file(cx) {
20337            let path = file.path().display(file.path_style(cx));
20338            cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
20339        }
20340    }
20341
20342    pub fn open_permalink_to_line(
20343        &mut self,
20344        _: &OpenPermalinkToLine,
20345        window: &mut Window,
20346        cx: &mut Context<Self>,
20347    ) {
20348        let permalink_task = self.get_permalink_to_line(cx);
20349        let workspace = self.workspace();
20350
20351        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
20352            Ok(permalink) => {
20353                cx.update(|_, cx| {
20354                    cx.open_url(permalink.as_ref());
20355                })
20356                .ok();
20357            }
20358            Err(err) => {
20359                let message = format!("Failed to open permalink: {err}");
20360
20361                anyhow::Result::<()>::Err(err).log_err();
20362
20363                if let Some(workspace) = workspace {
20364                    workspace
20365                        .update(cx, |workspace, cx| {
20366                            struct OpenPermalinkToLine;
20367
20368                            workspace.show_toast(
20369                                Toast::new(
20370                                    NotificationId::unique::<OpenPermalinkToLine>(),
20371                                    message,
20372                                ),
20373                                cx,
20374                            )
20375                        })
20376                        .ok();
20377                }
20378            }
20379        })
20380        .detach();
20381    }
20382
20383    pub fn insert_uuid_v4(
20384        &mut self,
20385        _: &InsertUuidV4,
20386        window: &mut Window,
20387        cx: &mut Context<Self>,
20388    ) {
20389        self.insert_uuid(UuidVersion::V4, window, cx);
20390    }
20391
20392    pub fn insert_uuid_v7(
20393        &mut self,
20394        _: &InsertUuidV7,
20395        window: &mut Window,
20396        cx: &mut Context<Self>,
20397    ) {
20398        self.insert_uuid(UuidVersion::V7, window, cx);
20399    }
20400
20401    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
20402        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
20403        self.transact(window, cx, |this, window, cx| {
20404            let edits = this
20405                .selections
20406                .all::<Point>(&this.display_snapshot(cx))
20407                .into_iter()
20408                .map(|selection| {
20409                    let uuid = match version {
20410                        UuidVersion::V4 => uuid::Uuid::new_v4(),
20411                        UuidVersion::V7 => uuid::Uuid::now_v7(),
20412                    };
20413
20414                    (selection.range(), uuid.to_string())
20415                });
20416            this.edit(edits, cx);
20417            this.refresh_edit_prediction(true, false, window, cx);
20418        });
20419    }
20420
20421    pub fn open_selections_in_multibuffer(
20422        &mut self,
20423        _: &OpenSelectionsInMultibuffer,
20424        window: &mut Window,
20425        cx: &mut Context<Self>,
20426    ) {
20427        let multibuffer = self.buffer.read(cx);
20428
20429        let Some(buffer) = multibuffer.as_singleton() else {
20430            return;
20431        };
20432
20433        let Some(workspace) = self.workspace() else {
20434            return;
20435        };
20436
20437        let title = multibuffer.title(cx).to_string();
20438
20439        let locations = self
20440            .selections
20441            .all_anchors(&self.display_snapshot(cx))
20442            .iter()
20443            .map(|selection| {
20444                (
20445                    buffer.clone(),
20446                    (selection.start.text_anchor..selection.end.text_anchor)
20447                        .to_point(buffer.read(cx)),
20448                )
20449            })
20450            .into_group_map();
20451
20452        cx.spawn_in(window, async move |_, cx| {
20453            workspace.update_in(cx, |workspace, window, cx| {
20454                Self::open_locations_in_multibuffer(
20455                    workspace,
20456                    locations,
20457                    format!("Selections for '{title}'"),
20458                    false,
20459                    MultibufferSelectionMode::All,
20460                    window,
20461                    cx,
20462                );
20463            })
20464        })
20465        .detach();
20466    }
20467
20468    /// Adds a row highlight for the given range. If a row has multiple highlights, the
20469    /// last highlight added will be used.
20470    ///
20471    /// If the range ends at the beginning of a line, then that line will not be highlighted.
20472    pub fn highlight_rows<T: 'static>(
20473        &mut self,
20474        range: Range<Anchor>,
20475        color: Hsla,
20476        options: RowHighlightOptions,
20477        cx: &mut Context<Self>,
20478    ) {
20479        let snapshot = self.buffer().read(cx).snapshot(cx);
20480        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
20481        let ix = row_highlights.binary_search_by(|highlight| {
20482            Ordering::Equal
20483                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
20484                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
20485        });
20486
20487        if let Err(mut ix) = ix {
20488            let index = post_inc(&mut self.highlight_order);
20489
20490            // If this range intersects with the preceding highlight, then merge it with
20491            // the preceding highlight. Otherwise insert a new highlight.
20492            let mut merged = false;
20493            if ix > 0 {
20494                let prev_highlight = &mut row_highlights[ix - 1];
20495                if prev_highlight
20496                    .range
20497                    .end
20498                    .cmp(&range.start, &snapshot)
20499                    .is_ge()
20500                {
20501                    ix -= 1;
20502                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
20503                        prev_highlight.range.end = range.end;
20504                    }
20505                    merged = true;
20506                    prev_highlight.index = index;
20507                    prev_highlight.color = color;
20508                    prev_highlight.options = options;
20509                }
20510            }
20511
20512            if !merged {
20513                row_highlights.insert(
20514                    ix,
20515                    RowHighlight {
20516                        range,
20517                        index,
20518                        color,
20519                        options,
20520                        type_id: TypeId::of::<T>(),
20521                    },
20522                );
20523            }
20524
20525            // If any of the following highlights intersect with this one, merge them.
20526            while let Some(next_highlight) = row_highlights.get(ix + 1) {
20527                let highlight = &row_highlights[ix];
20528                if next_highlight
20529                    .range
20530                    .start
20531                    .cmp(&highlight.range.end, &snapshot)
20532                    .is_le()
20533                {
20534                    if next_highlight
20535                        .range
20536                        .end
20537                        .cmp(&highlight.range.end, &snapshot)
20538                        .is_gt()
20539                    {
20540                        row_highlights[ix].range.end = next_highlight.range.end;
20541                    }
20542                    row_highlights.remove(ix + 1);
20543                } else {
20544                    break;
20545                }
20546            }
20547        }
20548    }
20549
20550    /// Remove any highlighted row ranges of the given type that intersect the
20551    /// given ranges.
20552    pub fn remove_highlighted_rows<T: 'static>(
20553        &mut self,
20554        ranges_to_remove: Vec<Range<Anchor>>,
20555        cx: &mut Context<Self>,
20556    ) {
20557        let snapshot = self.buffer().read(cx).snapshot(cx);
20558        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
20559        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
20560        row_highlights.retain(|highlight| {
20561            while let Some(range_to_remove) = ranges_to_remove.peek() {
20562                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
20563                    Ordering::Less | Ordering::Equal => {
20564                        ranges_to_remove.next();
20565                    }
20566                    Ordering::Greater => {
20567                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
20568                            Ordering::Less | Ordering::Equal => {
20569                                return false;
20570                            }
20571                            Ordering::Greater => break,
20572                        }
20573                    }
20574                }
20575            }
20576
20577            true
20578        })
20579    }
20580
20581    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
20582    pub fn clear_row_highlights<T: 'static>(&mut self) {
20583        self.highlighted_rows.remove(&TypeId::of::<T>());
20584    }
20585
20586    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
20587    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
20588        self.highlighted_rows
20589            .get(&TypeId::of::<T>())
20590            .map_or(&[] as &[_], |vec| vec.as_slice())
20591            .iter()
20592            .map(|highlight| (highlight.range.clone(), highlight.color))
20593    }
20594
20595    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
20596    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
20597    /// Allows to ignore certain kinds of highlights.
20598    pub fn highlighted_display_rows(
20599        &self,
20600        window: &mut Window,
20601        cx: &mut App,
20602    ) -> BTreeMap<DisplayRow, LineHighlight> {
20603        let snapshot = self.snapshot(window, cx);
20604        let mut used_highlight_orders = HashMap::default();
20605        self.highlighted_rows
20606            .iter()
20607            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
20608            .fold(
20609                BTreeMap::<DisplayRow, LineHighlight>::new(),
20610                |mut unique_rows, highlight| {
20611                    let start = highlight.range.start.to_display_point(&snapshot);
20612                    let end = highlight.range.end.to_display_point(&snapshot);
20613                    let start_row = start.row().0;
20614                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
20615                        && end.column() == 0
20616                    {
20617                        end.row().0.saturating_sub(1)
20618                    } else {
20619                        end.row().0
20620                    };
20621                    for row in start_row..=end_row {
20622                        let used_index =
20623                            used_highlight_orders.entry(row).or_insert(highlight.index);
20624                        if highlight.index >= *used_index {
20625                            *used_index = highlight.index;
20626                            unique_rows.insert(
20627                                DisplayRow(row),
20628                                LineHighlight {
20629                                    include_gutter: highlight.options.include_gutter,
20630                                    border: None,
20631                                    background: highlight.color.into(),
20632                                    type_id: Some(highlight.type_id),
20633                                },
20634                            );
20635                        }
20636                    }
20637                    unique_rows
20638                },
20639            )
20640    }
20641
20642    pub fn highlighted_display_row_for_autoscroll(
20643        &self,
20644        snapshot: &DisplaySnapshot,
20645    ) -> Option<DisplayRow> {
20646        self.highlighted_rows
20647            .values()
20648            .flat_map(|highlighted_rows| highlighted_rows.iter())
20649            .filter_map(|highlight| {
20650                if highlight.options.autoscroll {
20651                    Some(highlight.range.start.to_display_point(snapshot).row())
20652                } else {
20653                    None
20654                }
20655            })
20656            .min()
20657    }
20658
20659    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
20660        self.highlight_background::<SearchWithinRange>(
20661            ranges,
20662            |colors| colors.colors().editor_document_highlight_read_background,
20663            cx,
20664        )
20665    }
20666
20667    pub fn set_breadcrumb_header(&mut self, new_header: String) {
20668        self.breadcrumb_header = Some(new_header);
20669    }
20670
20671    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
20672        self.clear_background_highlights::<SearchWithinRange>(cx);
20673    }
20674
20675    pub fn highlight_background<T: 'static>(
20676        &mut self,
20677        ranges: &[Range<Anchor>],
20678        color_fetcher: fn(&Theme) -> Hsla,
20679        cx: &mut Context<Self>,
20680    ) {
20681        self.background_highlights.insert(
20682            HighlightKey::Type(TypeId::of::<T>()),
20683            (color_fetcher, Arc::from(ranges)),
20684        );
20685        self.scrollbar_marker_state.dirty = true;
20686        cx.notify();
20687    }
20688
20689    pub fn highlight_background_key<T: 'static>(
20690        &mut self,
20691        key: usize,
20692        ranges: &[Range<Anchor>],
20693        color_fetcher: fn(&Theme) -> Hsla,
20694        cx: &mut Context<Self>,
20695    ) {
20696        self.background_highlights.insert(
20697            HighlightKey::TypePlus(TypeId::of::<T>(), key),
20698            (color_fetcher, Arc::from(ranges)),
20699        );
20700        self.scrollbar_marker_state.dirty = true;
20701        cx.notify();
20702    }
20703
20704    pub fn clear_background_highlights<T: 'static>(
20705        &mut self,
20706        cx: &mut Context<Self>,
20707    ) -> Option<BackgroundHighlight> {
20708        let text_highlights = self
20709            .background_highlights
20710            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
20711        if !text_highlights.1.is_empty() {
20712            self.scrollbar_marker_state.dirty = true;
20713            cx.notify();
20714        }
20715        Some(text_highlights)
20716    }
20717
20718    pub fn highlight_gutter<T: 'static>(
20719        &mut self,
20720        ranges: impl Into<Vec<Range<Anchor>>>,
20721        color_fetcher: fn(&App) -> Hsla,
20722        cx: &mut Context<Self>,
20723    ) {
20724        self.gutter_highlights
20725            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
20726        cx.notify();
20727    }
20728
20729    pub fn clear_gutter_highlights<T: 'static>(
20730        &mut self,
20731        cx: &mut Context<Self>,
20732    ) -> Option<GutterHighlight> {
20733        cx.notify();
20734        self.gutter_highlights.remove(&TypeId::of::<T>())
20735    }
20736
20737    pub fn insert_gutter_highlight<T: 'static>(
20738        &mut self,
20739        range: Range<Anchor>,
20740        color_fetcher: fn(&App) -> Hsla,
20741        cx: &mut Context<Self>,
20742    ) {
20743        let snapshot = self.buffer().read(cx).snapshot(cx);
20744        let mut highlights = self
20745            .gutter_highlights
20746            .remove(&TypeId::of::<T>())
20747            .map(|(_, highlights)| highlights)
20748            .unwrap_or_default();
20749        let ix = highlights.binary_search_by(|highlight| {
20750            Ordering::Equal
20751                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
20752                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
20753        });
20754        if let Err(ix) = ix {
20755            highlights.insert(ix, range);
20756        }
20757        self.gutter_highlights
20758            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
20759    }
20760
20761    pub fn remove_gutter_highlights<T: 'static>(
20762        &mut self,
20763        ranges_to_remove: Vec<Range<Anchor>>,
20764        cx: &mut Context<Self>,
20765    ) {
20766        let snapshot = self.buffer().read(cx).snapshot(cx);
20767        let Some((color_fetcher, mut gutter_highlights)) =
20768            self.gutter_highlights.remove(&TypeId::of::<T>())
20769        else {
20770            return;
20771        };
20772        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
20773        gutter_highlights.retain(|highlight| {
20774            while let Some(range_to_remove) = ranges_to_remove.peek() {
20775                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
20776                    Ordering::Less | Ordering::Equal => {
20777                        ranges_to_remove.next();
20778                    }
20779                    Ordering::Greater => {
20780                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
20781                            Ordering::Less | Ordering::Equal => {
20782                                return false;
20783                            }
20784                            Ordering::Greater => break,
20785                        }
20786                    }
20787                }
20788            }
20789
20790            true
20791        });
20792        self.gutter_highlights
20793            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
20794    }
20795
20796    #[cfg(feature = "test-support")]
20797    pub fn all_text_highlights(
20798        &self,
20799        window: &mut Window,
20800        cx: &mut Context<Self>,
20801    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
20802        let snapshot = self.snapshot(window, cx);
20803        self.display_map.update(cx, |display_map, _| {
20804            display_map
20805                .all_text_highlights()
20806                .map(|highlight| {
20807                    let (style, ranges) = highlight.as_ref();
20808                    (
20809                        *style,
20810                        ranges
20811                            .iter()
20812                            .map(|range| range.clone().to_display_points(&snapshot))
20813                            .collect(),
20814                    )
20815                })
20816                .collect()
20817        })
20818    }
20819
20820    #[cfg(feature = "test-support")]
20821    pub fn all_text_background_highlights(
20822        &self,
20823        window: &mut Window,
20824        cx: &mut Context<Self>,
20825    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20826        let snapshot = self.snapshot(window, cx);
20827        let buffer = &snapshot.buffer_snapshot();
20828        let start = buffer.anchor_before(0);
20829        let end = buffer.anchor_after(buffer.len());
20830        self.sorted_background_highlights_in_range(start..end, &snapshot, cx.theme())
20831    }
20832
20833    #[cfg(any(test, feature = "test-support"))]
20834    pub fn sorted_background_highlights_in_range(
20835        &self,
20836        search_range: Range<Anchor>,
20837        display_snapshot: &DisplaySnapshot,
20838        theme: &Theme,
20839    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20840        let mut res = self.background_highlights_in_range(search_range, display_snapshot, theme);
20841        res.sort_by(|a, b| {
20842            a.0.start
20843                .cmp(&b.0.start)
20844                .then_with(|| a.0.end.cmp(&b.0.end))
20845                .then_with(|| a.1.cmp(&b.1))
20846        });
20847        res
20848    }
20849
20850    #[cfg(feature = "test-support")]
20851    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
20852        let snapshot = self.buffer().read(cx).snapshot(cx);
20853
20854        let highlights = self
20855            .background_highlights
20856            .get(&HighlightKey::Type(TypeId::of::<
20857                items::BufferSearchHighlights,
20858            >()));
20859
20860        if let Some((_color, ranges)) = highlights {
20861            ranges
20862                .iter()
20863                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
20864                .collect_vec()
20865        } else {
20866            vec![]
20867        }
20868    }
20869
20870    fn document_highlights_for_position<'a>(
20871        &'a self,
20872        position: Anchor,
20873        buffer: &'a MultiBufferSnapshot,
20874    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
20875        let read_highlights = self
20876            .background_highlights
20877            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
20878            .map(|h| &h.1);
20879        let write_highlights = self
20880            .background_highlights
20881            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
20882            .map(|h| &h.1);
20883        let left_position = position.bias_left(buffer);
20884        let right_position = position.bias_right(buffer);
20885        read_highlights
20886            .into_iter()
20887            .chain(write_highlights)
20888            .flat_map(move |ranges| {
20889                let start_ix = match ranges.binary_search_by(|probe| {
20890                    let cmp = probe.end.cmp(&left_position, buffer);
20891                    if cmp.is_ge() {
20892                        Ordering::Greater
20893                    } else {
20894                        Ordering::Less
20895                    }
20896                }) {
20897                    Ok(i) | Err(i) => i,
20898                };
20899
20900                ranges[start_ix..]
20901                    .iter()
20902                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
20903            })
20904    }
20905
20906    pub fn has_background_highlights<T: 'static>(&self) -> bool {
20907        self.background_highlights
20908            .get(&HighlightKey::Type(TypeId::of::<T>()))
20909            .is_some_and(|(_, highlights)| !highlights.is_empty())
20910    }
20911
20912    /// Returns all background highlights for a given range.
20913    ///
20914    /// The order of highlights is not deterministic, do sort the ranges if needed for the logic.
20915    pub fn background_highlights_in_range(
20916        &self,
20917        search_range: Range<Anchor>,
20918        display_snapshot: &DisplaySnapshot,
20919        theme: &Theme,
20920    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20921        let mut results = Vec::new();
20922        for (color_fetcher, ranges) in self.background_highlights.values() {
20923            let color = color_fetcher(theme);
20924            let start_ix = match ranges.binary_search_by(|probe| {
20925                let cmp = probe
20926                    .end
20927                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
20928                if cmp.is_gt() {
20929                    Ordering::Greater
20930                } else {
20931                    Ordering::Less
20932                }
20933            }) {
20934                Ok(i) | Err(i) => i,
20935            };
20936            for range in &ranges[start_ix..] {
20937                if range
20938                    .start
20939                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
20940                    .is_ge()
20941                {
20942                    break;
20943                }
20944
20945                let start = range.start.to_display_point(display_snapshot);
20946                let end = range.end.to_display_point(display_snapshot);
20947                results.push((start..end, color))
20948            }
20949        }
20950        results
20951    }
20952
20953    pub fn gutter_highlights_in_range(
20954        &self,
20955        search_range: Range<Anchor>,
20956        display_snapshot: &DisplaySnapshot,
20957        cx: &App,
20958    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20959        let mut results = Vec::new();
20960        for (color_fetcher, ranges) in self.gutter_highlights.values() {
20961            let color = color_fetcher(cx);
20962            let start_ix = match ranges.binary_search_by(|probe| {
20963                let cmp = probe
20964                    .end
20965                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
20966                if cmp.is_gt() {
20967                    Ordering::Greater
20968                } else {
20969                    Ordering::Less
20970                }
20971            }) {
20972                Ok(i) | Err(i) => i,
20973            };
20974            for range in &ranges[start_ix..] {
20975                if range
20976                    .start
20977                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
20978                    .is_ge()
20979                {
20980                    break;
20981                }
20982
20983                let start = range.start.to_display_point(display_snapshot);
20984                let end = range.end.to_display_point(display_snapshot);
20985                results.push((start..end, color))
20986            }
20987        }
20988        results
20989    }
20990
20991    /// Get the text ranges corresponding to the redaction query
20992    pub fn redacted_ranges(
20993        &self,
20994        search_range: Range<Anchor>,
20995        display_snapshot: &DisplaySnapshot,
20996        cx: &App,
20997    ) -> Vec<Range<DisplayPoint>> {
20998        display_snapshot
20999            .buffer_snapshot()
21000            .redacted_ranges(search_range, |file| {
21001                if let Some(file) = file {
21002                    file.is_private()
21003                        && EditorSettings::get(
21004                            Some(SettingsLocation {
21005                                worktree_id: file.worktree_id(cx),
21006                                path: file.path().as_ref(),
21007                            }),
21008                            cx,
21009                        )
21010                        .redact_private_values
21011                } else {
21012                    false
21013                }
21014            })
21015            .map(|range| {
21016                range.start.to_display_point(display_snapshot)
21017                    ..range.end.to_display_point(display_snapshot)
21018            })
21019            .collect()
21020    }
21021
21022    pub fn highlight_text_key<T: 'static>(
21023        &mut self,
21024        key: usize,
21025        ranges: Vec<Range<Anchor>>,
21026        style: HighlightStyle,
21027        cx: &mut Context<Self>,
21028    ) {
21029        self.display_map.update(cx, |map, _| {
21030            map.highlight_text(
21031                HighlightKey::TypePlus(TypeId::of::<T>(), key),
21032                ranges,
21033                style,
21034            );
21035        });
21036        cx.notify();
21037    }
21038
21039    pub fn highlight_text<T: 'static>(
21040        &mut self,
21041        ranges: Vec<Range<Anchor>>,
21042        style: HighlightStyle,
21043        cx: &mut Context<Self>,
21044    ) {
21045        self.display_map.update(cx, |map, _| {
21046            map.highlight_text(HighlightKey::Type(TypeId::of::<T>()), ranges, style)
21047        });
21048        cx.notify();
21049    }
21050
21051    pub fn text_highlights<'a, T: 'static>(
21052        &'a self,
21053        cx: &'a App,
21054    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
21055        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
21056    }
21057
21058    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
21059        let cleared = self
21060            .display_map
21061            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
21062        if cleared {
21063            cx.notify();
21064        }
21065    }
21066
21067    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
21068        (self.read_only(cx) || self.blink_manager.read(cx).visible())
21069            && self.focus_handle.is_focused(window)
21070    }
21071
21072    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
21073        self.show_cursor_when_unfocused = is_enabled;
21074        cx.notify();
21075    }
21076
21077    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
21078        cx.notify();
21079    }
21080
21081    fn on_debug_session_event(
21082        &mut self,
21083        _session: Entity<Session>,
21084        event: &SessionEvent,
21085        cx: &mut Context<Self>,
21086    ) {
21087        if let SessionEvent::InvalidateInlineValue = event {
21088            self.refresh_inline_values(cx);
21089        }
21090    }
21091
21092    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
21093        let Some(project) = self.project.clone() else {
21094            return;
21095        };
21096
21097        if !self.inline_value_cache.enabled {
21098            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
21099            self.splice_inlays(&inlays, Vec::new(), cx);
21100            return;
21101        }
21102
21103        let current_execution_position = self
21104            .highlighted_rows
21105            .get(&TypeId::of::<ActiveDebugLine>())
21106            .and_then(|lines| lines.last().map(|line| line.range.end));
21107
21108        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
21109            let inline_values = editor
21110                .update(cx, |editor, cx| {
21111                    let Some(current_execution_position) = current_execution_position else {
21112                        return Some(Task::ready(Ok(Vec::new())));
21113                    };
21114
21115                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
21116                        let snapshot = buffer.snapshot(cx);
21117
21118                        let excerpt = snapshot.excerpt_containing(
21119                            current_execution_position..current_execution_position,
21120                        )?;
21121
21122                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
21123                    })?;
21124
21125                    let range =
21126                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
21127
21128                    project.inline_values(buffer, range, cx)
21129                })
21130                .ok()
21131                .flatten()?
21132                .await
21133                .context("refreshing debugger inlays")
21134                .log_err()?;
21135
21136            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
21137
21138            for (buffer_id, inline_value) in inline_values
21139                .into_iter()
21140                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
21141            {
21142                buffer_inline_values
21143                    .entry(buffer_id)
21144                    .or_default()
21145                    .push(inline_value);
21146            }
21147
21148            editor
21149                .update(cx, |editor, cx| {
21150                    let snapshot = editor.buffer.read(cx).snapshot(cx);
21151                    let mut new_inlays = Vec::default();
21152
21153                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
21154                        let buffer_id = buffer_snapshot.remote_id();
21155                        buffer_inline_values
21156                            .get(&buffer_id)
21157                            .into_iter()
21158                            .flatten()
21159                            .for_each(|hint| {
21160                                let inlay = Inlay::debugger(
21161                                    post_inc(&mut editor.next_inlay_id),
21162                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
21163                                    hint.text(),
21164                                );
21165                                if !inlay.text().chars().contains(&'\n') {
21166                                    new_inlays.push(inlay);
21167                                }
21168                            });
21169                    }
21170
21171                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
21172                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
21173
21174                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
21175                })
21176                .ok()?;
21177            Some(())
21178        });
21179    }
21180
21181    fn on_buffer_event(
21182        &mut self,
21183        multibuffer: &Entity<MultiBuffer>,
21184        event: &multi_buffer::Event,
21185        window: &mut Window,
21186        cx: &mut Context<Self>,
21187    ) {
21188        match event {
21189            multi_buffer::Event::Edited { edited_buffer } => {
21190                self.scrollbar_marker_state.dirty = true;
21191                self.active_indent_guides_state.dirty = true;
21192                self.refresh_active_diagnostics(cx);
21193                self.refresh_code_actions(window, cx);
21194                self.refresh_selected_text_highlights(true, window, cx);
21195                self.refresh_single_line_folds(window, cx);
21196                self.refresh_matching_bracket_highlights(window, cx);
21197                if self.has_active_edit_prediction() {
21198                    self.update_visible_edit_prediction(window, cx);
21199                }
21200
21201                if let Some(buffer) = edited_buffer {
21202                    if buffer.read(cx).file().is_none() {
21203                        cx.emit(EditorEvent::TitleChanged);
21204                    }
21205
21206                    if self.project.is_some() {
21207                        let buffer_id = buffer.read(cx).remote_id();
21208                        self.register_buffer(buffer_id, cx);
21209                        self.update_lsp_data(Some(buffer_id), window, cx);
21210                        self.refresh_inlay_hints(
21211                            InlayHintRefreshReason::BufferEdited(buffer_id),
21212                            cx,
21213                        );
21214                    }
21215                }
21216
21217                cx.emit(EditorEvent::BufferEdited);
21218                cx.emit(SearchEvent::MatchesInvalidated);
21219
21220                let Some(project) = &self.project else { return };
21221                let (telemetry, is_via_ssh) = {
21222                    let project = project.read(cx);
21223                    let telemetry = project.client().telemetry().clone();
21224                    let is_via_ssh = project.is_via_remote_server();
21225                    (telemetry, is_via_ssh)
21226                };
21227                telemetry.log_edit_event("editor", is_via_ssh);
21228            }
21229            multi_buffer::Event::ExcerptsAdded {
21230                buffer,
21231                predecessor,
21232                excerpts,
21233            } => {
21234                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21235                let buffer_id = buffer.read(cx).remote_id();
21236                if self.buffer.read(cx).diff_for(buffer_id).is_none()
21237                    && let Some(project) = &self.project
21238                {
21239                    update_uncommitted_diff_for_buffer(
21240                        cx.entity(),
21241                        project,
21242                        [buffer.clone()],
21243                        self.buffer.clone(),
21244                        cx,
21245                    )
21246                    .detach();
21247                }
21248                self.update_lsp_data(Some(buffer_id), window, cx);
21249                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
21250                cx.emit(EditorEvent::ExcerptsAdded {
21251                    buffer: buffer.clone(),
21252                    predecessor: *predecessor,
21253                    excerpts: excerpts.clone(),
21254                });
21255            }
21256            multi_buffer::Event::ExcerptsRemoved {
21257                ids,
21258                removed_buffer_ids,
21259            } => {
21260                if let Some(inlay_hints) = &mut self.inlay_hints {
21261                    inlay_hints.remove_inlay_chunk_data(removed_buffer_ids);
21262                }
21263                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
21264                for buffer_id in removed_buffer_ids {
21265                    self.registered_buffers.remove(buffer_id);
21266                }
21267                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
21268                cx.emit(EditorEvent::ExcerptsRemoved {
21269                    ids: ids.clone(),
21270                    removed_buffer_ids: removed_buffer_ids.clone(),
21271                });
21272            }
21273            multi_buffer::Event::ExcerptsEdited {
21274                excerpt_ids,
21275                buffer_ids,
21276            } => {
21277                self.display_map.update(cx, |map, cx| {
21278                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
21279                });
21280                cx.emit(EditorEvent::ExcerptsEdited {
21281                    ids: excerpt_ids.clone(),
21282                });
21283            }
21284            multi_buffer::Event::ExcerptsExpanded { ids } => {
21285                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
21286                self.refresh_document_highlights(cx);
21287                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
21288            }
21289            multi_buffer::Event::Reparsed(buffer_id) => {
21290                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21291                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
21292
21293                cx.emit(EditorEvent::Reparsed(*buffer_id));
21294            }
21295            multi_buffer::Event::DiffHunksToggled => {
21296                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21297            }
21298            multi_buffer::Event::LanguageChanged(buffer_id) => {
21299                self.registered_buffers.remove(&buffer_id);
21300                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
21301                cx.emit(EditorEvent::Reparsed(*buffer_id));
21302                cx.notify();
21303            }
21304            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
21305            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
21306            multi_buffer::Event::FileHandleChanged
21307            | multi_buffer::Event::Reloaded
21308            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
21309            multi_buffer::Event::DiagnosticsUpdated => {
21310                self.update_diagnostics_state(window, cx);
21311            }
21312            _ => {}
21313        };
21314    }
21315
21316    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
21317        if !self.diagnostics_enabled() {
21318            return;
21319        }
21320        self.refresh_active_diagnostics(cx);
21321        self.refresh_inline_diagnostics(true, window, cx);
21322        self.scrollbar_marker_state.dirty = true;
21323        cx.notify();
21324    }
21325
21326    pub fn start_temporary_diff_override(&mut self) {
21327        self.load_diff_task.take();
21328        self.temporary_diff_override = true;
21329    }
21330
21331    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
21332        self.temporary_diff_override = false;
21333        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
21334        self.buffer.update(cx, |buffer, cx| {
21335            buffer.set_all_diff_hunks_collapsed(cx);
21336        });
21337
21338        if let Some(project) = self.project.clone() {
21339            self.load_diff_task = Some(
21340                update_uncommitted_diff_for_buffer(
21341                    cx.entity(),
21342                    &project,
21343                    self.buffer.read(cx).all_buffers(),
21344                    self.buffer.clone(),
21345                    cx,
21346                )
21347                .shared(),
21348            );
21349        }
21350    }
21351
21352    fn on_display_map_changed(
21353        &mut self,
21354        _: Entity<DisplayMap>,
21355        _: &mut Window,
21356        cx: &mut Context<Self>,
21357    ) {
21358        cx.notify();
21359    }
21360
21361    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21362        if self.diagnostics_enabled() {
21363            let new_severity = EditorSettings::get_global(cx)
21364                .diagnostics_max_severity
21365                .unwrap_or(DiagnosticSeverity::Hint);
21366            self.set_max_diagnostics_severity(new_severity, cx);
21367        }
21368        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21369        self.update_edit_prediction_settings(cx);
21370        self.refresh_edit_prediction(true, false, window, cx);
21371        self.refresh_inline_values(cx);
21372        self.refresh_inlay_hints(
21373            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
21374                self.selections.newest_anchor().head(),
21375                &self.buffer.read(cx).snapshot(cx),
21376                cx,
21377            )),
21378            cx,
21379        );
21380
21381        let old_cursor_shape = self.cursor_shape;
21382        let old_show_breadcrumbs = self.show_breadcrumbs;
21383
21384        {
21385            let editor_settings = EditorSettings::get_global(cx);
21386            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
21387            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
21388            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
21389            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
21390        }
21391
21392        if old_cursor_shape != self.cursor_shape {
21393            cx.emit(EditorEvent::CursorShapeChanged);
21394        }
21395
21396        if old_show_breadcrumbs != self.show_breadcrumbs {
21397            cx.emit(EditorEvent::BreadcrumbsChanged);
21398        }
21399
21400        let project_settings = ProjectSettings::get_global(cx);
21401        self.buffer_serialization = self
21402            .should_serialize_buffer()
21403            .then(|| BufferSerialization::new(project_settings.session.restore_unsaved_buffers));
21404
21405        if self.mode.is_full() {
21406            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
21407            let inline_blame_enabled = project_settings.git.inline_blame.enabled;
21408            if self.show_inline_diagnostics != show_inline_diagnostics {
21409                self.show_inline_diagnostics = show_inline_diagnostics;
21410                self.refresh_inline_diagnostics(false, window, cx);
21411            }
21412
21413            if self.git_blame_inline_enabled != inline_blame_enabled {
21414                self.toggle_git_blame_inline_internal(false, window, cx);
21415            }
21416
21417            let minimap_settings = EditorSettings::get_global(cx).minimap;
21418            if self.minimap_visibility != MinimapVisibility::Disabled {
21419                if self.minimap_visibility.settings_visibility()
21420                    != minimap_settings.minimap_enabled()
21421                {
21422                    self.set_minimap_visibility(
21423                        MinimapVisibility::for_mode(self.mode(), cx),
21424                        window,
21425                        cx,
21426                    );
21427                } else if let Some(minimap_entity) = self.minimap.as_ref() {
21428                    minimap_entity.update(cx, |minimap_editor, cx| {
21429                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
21430                    })
21431                }
21432            }
21433        }
21434
21435        if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
21436            colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
21437        }) {
21438            if !inlay_splice.is_empty() {
21439                self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
21440            }
21441            self.refresh_colors_for_visible_range(None, window, cx);
21442        }
21443
21444        cx.notify();
21445    }
21446
21447    pub fn set_searchable(&mut self, searchable: bool) {
21448        self.searchable = searchable;
21449    }
21450
21451    pub fn searchable(&self) -> bool {
21452        self.searchable
21453    }
21454
21455    pub fn open_excerpts_in_split(
21456        &mut self,
21457        _: &OpenExcerptsSplit,
21458        window: &mut Window,
21459        cx: &mut Context<Self>,
21460    ) {
21461        self.open_excerpts_common(None, true, window, cx)
21462    }
21463
21464    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
21465        self.open_excerpts_common(None, false, window, cx)
21466    }
21467
21468    fn open_excerpts_common(
21469        &mut self,
21470        jump_data: Option<JumpData>,
21471        split: bool,
21472        window: &mut Window,
21473        cx: &mut Context<Self>,
21474    ) {
21475        let Some(workspace) = self.workspace() else {
21476            cx.propagate();
21477            return;
21478        };
21479
21480        if self.buffer.read(cx).is_singleton() {
21481            cx.propagate();
21482            return;
21483        }
21484
21485        let mut new_selections_by_buffer = HashMap::default();
21486        match &jump_data {
21487            Some(JumpData::MultiBufferPoint {
21488                excerpt_id,
21489                position,
21490                anchor,
21491                line_offset_from_top,
21492            }) => {
21493                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
21494                if let Some(buffer) = multi_buffer_snapshot
21495                    .buffer_id_for_excerpt(*excerpt_id)
21496                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
21497                {
21498                    let buffer_snapshot = buffer.read(cx).snapshot();
21499                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
21500                        language::ToPoint::to_point(anchor, &buffer_snapshot)
21501                    } else {
21502                        buffer_snapshot.clip_point(*position, Bias::Left)
21503                    };
21504                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
21505                    new_selections_by_buffer.insert(
21506                        buffer,
21507                        (
21508                            vec![jump_to_offset..jump_to_offset],
21509                            Some(*line_offset_from_top),
21510                        ),
21511                    );
21512                }
21513            }
21514            Some(JumpData::MultiBufferRow {
21515                row,
21516                line_offset_from_top,
21517            }) => {
21518                let point = MultiBufferPoint::new(row.0, 0);
21519                if let Some((buffer, buffer_point, _)) =
21520                    self.buffer.read(cx).point_to_buffer_point(point, cx)
21521                {
21522                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
21523                    new_selections_by_buffer
21524                        .entry(buffer)
21525                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
21526                        .0
21527                        .push(buffer_offset..buffer_offset)
21528                }
21529            }
21530            None => {
21531                let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
21532                let multi_buffer = self.buffer.read(cx);
21533                for selection in selections {
21534                    for (snapshot, range, _, anchor) in multi_buffer
21535                        .snapshot(cx)
21536                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
21537                    {
21538                        if let Some(anchor) = anchor {
21539                            let Some(buffer_handle) = multi_buffer.buffer_for_anchor(anchor, cx)
21540                            else {
21541                                continue;
21542                            };
21543                            let offset = text::ToOffset::to_offset(
21544                                &anchor.text_anchor,
21545                                &buffer_handle.read(cx).snapshot(),
21546                            );
21547                            let range = offset..offset;
21548                            new_selections_by_buffer
21549                                .entry(buffer_handle)
21550                                .or_insert((Vec::new(), None))
21551                                .0
21552                                .push(range)
21553                        } else {
21554                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
21555                            else {
21556                                continue;
21557                            };
21558                            new_selections_by_buffer
21559                                .entry(buffer_handle)
21560                                .or_insert((Vec::new(), None))
21561                                .0
21562                                .push(range)
21563                        }
21564                    }
21565                }
21566            }
21567        }
21568
21569        new_selections_by_buffer
21570            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
21571
21572        if new_selections_by_buffer.is_empty() {
21573            return;
21574        }
21575
21576        // We defer the pane interaction because we ourselves are a workspace item
21577        // and activating a new item causes the pane to call a method on us reentrantly,
21578        // which panics if we're on the stack.
21579        window.defer(cx, move |window, cx| {
21580            workspace.update(cx, |workspace, cx| {
21581                let pane = if split {
21582                    workspace.adjacent_pane(window, cx)
21583                } else {
21584                    workspace.active_pane().clone()
21585                };
21586
21587                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
21588                    let editor = buffer
21589                        .read(cx)
21590                        .file()
21591                        .is_none()
21592                        .then(|| {
21593                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
21594                            // so `workspace.open_project_item` will never find them, always opening a new editor.
21595                            // Instead, we try to activate the existing editor in the pane first.
21596                            let (editor, pane_item_index) =
21597                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
21598                                    let editor = item.downcast::<Editor>()?;
21599                                    let singleton_buffer =
21600                                        editor.read(cx).buffer().read(cx).as_singleton()?;
21601                                    if singleton_buffer == buffer {
21602                                        Some((editor, i))
21603                                    } else {
21604                                        None
21605                                    }
21606                                })?;
21607                            pane.update(cx, |pane, cx| {
21608                                pane.activate_item(pane_item_index, true, true, window, cx)
21609                            });
21610                            Some(editor)
21611                        })
21612                        .flatten()
21613                        .unwrap_or_else(|| {
21614                            workspace.open_project_item::<Self>(
21615                                pane.clone(),
21616                                buffer,
21617                                true,
21618                                true,
21619                                window,
21620                                cx,
21621                            )
21622                        });
21623
21624                    editor.update(cx, |editor, cx| {
21625                        let autoscroll = match scroll_offset {
21626                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
21627                            None => Autoscroll::newest(),
21628                        };
21629                        let nav_history = editor.nav_history.take();
21630                        editor.change_selections(
21631                            SelectionEffects::scroll(autoscroll),
21632                            window,
21633                            cx,
21634                            |s| {
21635                                s.select_ranges(ranges);
21636                            },
21637                        );
21638                        editor.nav_history = nav_history;
21639                    });
21640                }
21641            })
21642        });
21643    }
21644
21645    // For now, don't allow opening excerpts in buffers that aren't backed by
21646    // regular project files.
21647    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
21648        file.is_none_or(|file| project::File::from_dyn(Some(file)).is_some())
21649    }
21650
21651    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
21652        let snapshot = self.buffer.read(cx).read(cx);
21653        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
21654        Some(
21655            ranges
21656                .iter()
21657                .map(move |range| {
21658                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
21659                })
21660                .collect(),
21661        )
21662    }
21663
21664    fn selection_replacement_ranges(
21665        &self,
21666        range: Range<OffsetUtf16>,
21667        cx: &mut App,
21668    ) -> Vec<Range<OffsetUtf16>> {
21669        let selections = self
21670            .selections
21671            .all::<OffsetUtf16>(&self.display_snapshot(cx));
21672        let newest_selection = selections
21673            .iter()
21674            .max_by_key(|selection| selection.id)
21675            .unwrap();
21676        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
21677        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
21678        let snapshot = self.buffer.read(cx).read(cx);
21679        selections
21680            .into_iter()
21681            .map(|mut selection| {
21682                selection.start.0 =
21683                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
21684                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
21685                snapshot.clip_offset_utf16(selection.start, Bias::Left)
21686                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
21687            })
21688            .collect()
21689    }
21690
21691    fn report_editor_event(
21692        &self,
21693        reported_event: ReportEditorEvent,
21694        file_extension: Option<String>,
21695        cx: &App,
21696    ) {
21697        if cfg!(any(test, feature = "test-support")) {
21698            return;
21699        }
21700
21701        let Some(project) = &self.project else { return };
21702
21703        // If None, we are in a file without an extension
21704        let file = self
21705            .buffer
21706            .read(cx)
21707            .as_singleton()
21708            .and_then(|b| b.read(cx).file());
21709        let file_extension = file_extension.or(file
21710            .as_ref()
21711            .and_then(|file| Path::new(file.file_name(cx)).extension())
21712            .and_then(|e| e.to_str())
21713            .map(|a| a.to_string()));
21714
21715        let vim_mode = vim_mode_setting::VimModeSetting::try_get(cx)
21716            .map(|vim_mode| vim_mode.0)
21717            .unwrap_or(false);
21718
21719        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
21720        let copilot_enabled = edit_predictions_provider
21721            == language::language_settings::EditPredictionProvider::Copilot;
21722        let copilot_enabled_for_language = self
21723            .buffer
21724            .read(cx)
21725            .language_settings(cx)
21726            .show_edit_predictions;
21727
21728        let project = project.read(cx);
21729        let event_type = reported_event.event_type();
21730
21731        if let ReportEditorEvent::Saved { auto_saved } = reported_event {
21732            telemetry::event!(
21733                event_type,
21734                type = if auto_saved {"autosave"} else {"manual"},
21735                file_extension,
21736                vim_mode,
21737                copilot_enabled,
21738                copilot_enabled_for_language,
21739                edit_predictions_provider,
21740                is_via_ssh = project.is_via_remote_server(),
21741            );
21742        } else {
21743            telemetry::event!(
21744                event_type,
21745                file_extension,
21746                vim_mode,
21747                copilot_enabled,
21748                copilot_enabled_for_language,
21749                edit_predictions_provider,
21750                is_via_ssh = project.is_via_remote_server(),
21751            );
21752        };
21753    }
21754
21755    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
21756    /// with each line being an array of {text, highlight} objects.
21757    fn copy_highlight_json(
21758        &mut self,
21759        _: &CopyHighlightJson,
21760        window: &mut Window,
21761        cx: &mut Context<Self>,
21762    ) {
21763        #[derive(Serialize)]
21764        struct Chunk<'a> {
21765            text: String,
21766            highlight: Option<&'a str>,
21767        }
21768
21769        let snapshot = self.buffer.read(cx).snapshot(cx);
21770        let range = self
21771            .selected_text_range(false, window, cx)
21772            .and_then(|selection| {
21773                if selection.range.is_empty() {
21774                    None
21775                } else {
21776                    Some(
21777                        snapshot.offset_utf16_to_offset(OffsetUtf16(selection.range.start))
21778                            ..snapshot.offset_utf16_to_offset(OffsetUtf16(selection.range.end)),
21779                    )
21780                }
21781            })
21782            .unwrap_or_else(|| 0..snapshot.len());
21783
21784        let chunks = snapshot.chunks(range, true);
21785        let mut lines = Vec::new();
21786        let mut line: VecDeque<Chunk> = VecDeque::new();
21787
21788        let Some(style) = self.style.as_ref() else {
21789            return;
21790        };
21791
21792        for chunk in chunks {
21793            let highlight = chunk
21794                .syntax_highlight_id
21795                .and_then(|id| id.name(&style.syntax));
21796            let mut chunk_lines = chunk.text.split('\n').peekable();
21797            while let Some(text) = chunk_lines.next() {
21798                let mut merged_with_last_token = false;
21799                if let Some(last_token) = line.back_mut()
21800                    && last_token.highlight == highlight
21801                {
21802                    last_token.text.push_str(text);
21803                    merged_with_last_token = true;
21804                }
21805
21806                if !merged_with_last_token {
21807                    line.push_back(Chunk {
21808                        text: text.into(),
21809                        highlight,
21810                    });
21811                }
21812
21813                if chunk_lines.peek().is_some() {
21814                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
21815                        line.pop_front();
21816                    }
21817                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
21818                        line.pop_back();
21819                    }
21820
21821                    lines.push(mem::take(&mut line));
21822                }
21823            }
21824        }
21825
21826        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
21827            return;
21828        };
21829        cx.write_to_clipboard(ClipboardItem::new_string(lines));
21830    }
21831
21832    pub fn open_context_menu(
21833        &mut self,
21834        _: &OpenContextMenu,
21835        window: &mut Window,
21836        cx: &mut Context<Self>,
21837    ) {
21838        self.request_autoscroll(Autoscroll::newest(), cx);
21839        let position = self
21840            .selections
21841            .newest_display(&self.display_snapshot(cx))
21842            .start;
21843        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
21844    }
21845
21846    pub fn replay_insert_event(
21847        &mut self,
21848        text: &str,
21849        relative_utf16_range: Option<Range<isize>>,
21850        window: &mut Window,
21851        cx: &mut Context<Self>,
21852    ) {
21853        if !self.input_enabled {
21854            cx.emit(EditorEvent::InputIgnored { text: text.into() });
21855            return;
21856        }
21857        if let Some(relative_utf16_range) = relative_utf16_range {
21858            let selections = self
21859                .selections
21860                .all::<OffsetUtf16>(&self.display_snapshot(cx));
21861            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21862                let new_ranges = selections.into_iter().map(|range| {
21863                    let start = OffsetUtf16(
21864                        range
21865                            .head()
21866                            .0
21867                            .saturating_add_signed(relative_utf16_range.start),
21868                    );
21869                    let end = OffsetUtf16(
21870                        range
21871                            .head()
21872                            .0
21873                            .saturating_add_signed(relative_utf16_range.end),
21874                    );
21875                    start..end
21876                });
21877                s.select_ranges(new_ranges);
21878            });
21879        }
21880
21881        self.handle_input(text, window, cx);
21882    }
21883
21884    pub fn is_focused(&self, window: &Window) -> bool {
21885        self.focus_handle.is_focused(window)
21886    }
21887
21888    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21889        cx.emit(EditorEvent::Focused);
21890
21891        if let Some(descendant) = self
21892            .last_focused_descendant
21893            .take()
21894            .and_then(|descendant| descendant.upgrade())
21895        {
21896            window.focus(&descendant);
21897        } else {
21898            if let Some(blame) = self.blame.as_ref() {
21899                blame.update(cx, GitBlame::focus)
21900            }
21901
21902            self.blink_manager.update(cx, BlinkManager::enable);
21903            self.show_cursor_names(window, cx);
21904            self.buffer.update(cx, |buffer, cx| {
21905                buffer.finalize_last_transaction(cx);
21906                if self.leader_id.is_none() {
21907                    buffer.set_active_selections(
21908                        &self.selections.disjoint_anchors_arc(),
21909                        self.selections.line_mode(),
21910                        self.cursor_shape,
21911                        cx,
21912                    );
21913                }
21914            });
21915        }
21916    }
21917
21918    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
21919        cx.emit(EditorEvent::FocusedIn)
21920    }
21921
21922    fn handle_focus_out(
21923        &mut self,
21924        event: FocusOutEvent,
21925        _window: &mut Window,
21926        cx: &mut Context<Self>,
21927    ) {
21928        if event.blurred != self.focus_handle {
21929            self.last_focused_descendant = Some(event.blurred);
21930        }
21931        self.selection_drag_state = SelectionDragState::None;
21932        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
21933    }
21934
21935    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21936        self.blink_manager.update(cx, BlinkManager::disable);
21937        self.buffer
21938            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
21939
21940        if let Some(blame) = self.blame.as_ref() {
21941            blame.update(cx, GitBlame::blur)
21942        }
21943        if !self.hover_state.focused(window, cx) {
21944            hide_hover(self, cx);
21945        }
21946        if !self
21947            .context_menu
21948            .borrow()
21949            .as_ref()
21950            .is_some_and(|context_menu| context_menu.focused(window, cx))
21951        {
21952            self.hide_context_menu(window, cx);
21953        }
21954        self.take_active_edit_prediction(cx);
21955        cx.emit(EditorEvent::Blurred);
21956        cx.notify();
21957    }
21958
21959    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21960        let mut pending: String = window
21961            .pending_input_keystrokes()
21962            .into_iter()
21963            .flatten()
21964            .filter_map(|keystroke| {
21965                if keystroke.modifiers.is_subset_of(&Modifiers::shift()) {
21966                    keystroke.key_char.clone()
21967                } else {
21968                    None
21969                }
21970            })
21971            .collect();
21972
21973        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
21974            pending = "".to_string();
21975        }
21976
21977        let existing_pending = self
21978            .text_highlights::<PendingInput>(cx)
21979            .map(|(_, ranges)| ranges.to_vec());
21980        if existing_pending.is_none() && pending.is_empty() {
21981            return;
21982        }
21983        let transaction =
21984            self.transact(window, cx, |this, window, cx| {
21985                let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
21986                let edits = selections
21987                    .iter()
21988                    .map(|selection| (selection.end..selection.end, pending.clone()));
21989                this.edit(edits, cx);
21990                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21991                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
21992                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
21993                    }));
21994                });
21995                if let Some(existing_ranges) = existing_pending {
21996                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
21997                    this.edit(edits, cx);
21998                }
21999            });
22000
22001        let snapshot = self.snapshot(window, cx);
22002        let ranges = self
22003            .selections
22004            .all::<usize>(&snapshot.display_snapshot)
22005            .into_iter()
22006            .map(|selection| {
22007                snapshot.buffer_snapshot().anchor_after(selection.end)
22008                    ..snapshot
22009                        .buffer_snapshot()
22010                        .anchor_before(selection.end + pending.len())
22011            })
22012            .collect();
22013
22014        if pending.is_empty() {
22015            self.clear_highlights::<PendingInput>(cx);
22016        } else {
22017            self.highlight_text::<PendingInput>(
22018                ranges,
22019                HighlightStyle {
22020                    underline: Some(UnderlineStyle {
22021                        thickness: px(1.),
22022                        color: None,
22023                        wavy: false,
22024                    }),
22025                    ..Default::default()
22026                },
22027                cx,
22028            );
22029        }
22030
22031        self.ime_transaction = self.ime_transaction.or(transaction);
22032        if let Some(transaction) = self.ime_transaction {
22033            self.buffer.update(cx, |buffer, cx| {
22034                buffer.group_until_transaction(transaction, cx);
22035            });
22036        }
22037
22038        if self.text_highlights::<PendingInput>(cx).is_none() {
22039            self.ime_transaction.take();
22040        }
22041    }
22042
22043    pub fn register_action_renderer(
22044        &mut self,
22045        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
22046    ) -> Subscription {
22047        let id = self.next_editor_action_id.post_inc();
22048        self.editor_actions
22049            .borrow_mut()
22050            .insert(id, Box::new(listener));
22051
22052        let editor_actions = self.editor_actions.clone();
22053        Subscription::new(move || {
22054            editor_actions.borrow_mut().remove(&id);
22055        })
22056    }
22057
22058    pub fn register_action<A: Action>(
22059        &mut self,
22060        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
22061    ) -> Subscription {
22062        let id = self.next_editor_action_id.post_inc();
22063        let listener = Arc::new(listener);
22064        self.editor_actions.borrow_mut().insert(
22065            id,
22066            Box::new(move |_, window, _| {
22067                let listener = listener.clone();
22068                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
22069                    let action = action.downcast_ref().unwrap();
22070                    if phase == DispatchPhase::Bubble {
22071                        listener(action, window, cx)
22072                    }
22073                })
22074            }),
22075        );
22076
22077        let editor_actions = self.editor_actions.clone();
22078        Subscription::new(move || {
22079            editor_actions.borrow_mut().remove(&id);
22080        })
22081    }
22082
22083    pub fn file_header_size(&self) -> u32 {
22084        FILE_HEADER_HEIGHT
22085    }
22086
22087    pub fn restore(
22088        &mut self,
22089        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
22090        window: &mut Window,
22091        cx: &mut Context<Self>,
22092    ) {
22093        let workspace = self.workspace();
22094        let project = self.project();
22095        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
22096            let mut tasks = Vec::new();
22097            for (buffer_id, changes) in revert_changes {
22098                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
22099                    buffer.update(cx, |buffer, cx| {
22100                        buffer.edit(
22101                            changes
22102                                .into_iter()
22103                                .map(|(range, text)| (range, text.to_string())),
22104                            None,
22105                            cx,
22106                        );
22107                    });
22108
22109                    if let Some(project) =
22110                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
22111                    {
22112                        project.update(cx, |project, cx| {
22113                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
22114                        })
22115                    }
22116                }
22117            }
22118            tasks
22119        });
22120        cx.spawn_in(window, async move |_, cx| {
22121            for (buffer, task) in save_tasks {
22122                let result = task.await;
22123                if result.is_err() {
22124                    let Some(path) = buffer
22125                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
22126                        .ok()
22127                    else {
22128                        continue;
22129                    };
22130                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
22131                        let Some(task) = cx
22132                            .update_window_entity(workspace, |workspace, window, cx| {
22133                                workspace
22134                                    .open_path_preview(path, None, false, false, false, window, cx)
22135                            })
22136                            .ok()
22137                        else {
22138                            continue;
22139                        };
22140                        task.await.log_err();
22141                    }
22142                }
22143            }
22144        })
22145        .detach();
22146        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
22147            selections.refresh()
22148        });
22149    }
22150
22151    pub fn to_pixel_point(
22152        &self,
22153        source: multi_buffer::Anchor,
22154        editor_snapshot: &EditorSnapshot,
22155        window: &mut Window,
22156    ) -> Option<gpui::Point<Pixels>> {
22157        let source_point = source.to_display_point(editor_snapshot);
22158        self.display_to_pixel_point(source_point, editor_snapshot, window)
22159    }
22160
22161    pub fn display_to_pixel_point(
22162        &self,
22163        source: DisplayPoint,
22164        editor_snapshot: &EditorSnapshot,
22165        window: &mut Window,
22166    ) -> Option<gpui::Point<Pixels>> {
22167        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
22168        let text_layout_details = self.text_layout_details(window);
22169        let scroll_top = text_layout_details
22170            .scroll_anchor
22171            .scroll_position(editor_snapshot)
22172            .y;
22173
22174        if source.row().as_f64() < scroll_top.floor() {
22175            return None;
22176        }
22177        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
22178        let source_y = line_height * (source.row().as_f64() - scroll_top) as f32;
22179        Some(gpui::Point::new(source_x, source_y))
22180    }
22181
22182    pub fn has_visible_completions_menu(&self) -> bool {
22183        !self.edit_prediction_preview_is_active()
22184            && self.context_menu.borrow().as_ref().is_some_and(|menu| {
22185                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
22186            })
22187    }
22188
22189    pub fn register_addon<T: Addon>(&mut self, instance: T) {
22190        if self.mode.is_minimap() {
22191            return;
22192        }
22193        self.addons
22194            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
22195    }
22196
22197    pub fn unregister_addon<T: Addon>(&mut self) {
22198        self.addons.remove(&std::any::TypeId::of::<T>());
22199    }
22200
22201    pub fn addon<T: Addon>(&self) -> Option<&T> {
22202        let type_id = std::any::TypeId::of::<T>();
22203        self.addons
22204            .get(&type_id)
22205            .and_then(|item| item.to_any().downcast_ref::<T>())
22206    }
22207
22208    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
22209        let type_id = std::any::TypeId::of::<T>();
22210        self.addons
22211            .get_mut(&type_id)
22212            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
22213    }
22214
22215    fn character_dimensions(&self, window: &mut Window) -> CharacterDimensions {
22216        let text_layout_details = self.text_layout_details(window);
22217        let style = &text_layout_details.editor_style;
22218        let font_id = window.text_system().resolve_font(&style.text.font());
22219        let font_size = style.text.font_size.to_pixels(window.rem_size());
22220        let line_height = style.text.line_height_in_pixels(window.rem_size());
22221        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
22222        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
22223
22224        CharacterDimensions {
22225            em_width,
22226            em_advance,
22227            line_height,
22228        }
22229    }
22230
22231    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
22232        self.load_diff_task.clone()
22233    }
22234
22235    fn read_metadata_from_db(
22236        &mut self,
22237        item_id: u64,
22238        workspace_id: WorkspaceId,
22239        window: &mut Window,
22240        cx: &mut Context<Editor>,
22241    ) {
22242        if self.buffer_kind(cx) == ItemBufferKind::Singleton
22243            && !self.mode.is_minimap()
22244            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
22245        {
22246            let buffer_snapshot = OnceCell::new();
22247
22248            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err()
22249                && !folds.is_empty()
22250            {
22251                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
22252                self.fold_ranges(
22253                    folds
22254                        .into_iter()
22255                        .map(|(start, end)| {
22256                            snapshot.clip_offset(start, Bias::Left)
22257                                ..snapshot.clip_offset(end, Bias::Right)
22258                        })
22259                        .collect(),
22260                    false,
22261                    window,
22262                    cx,
22263                );
22264            }
22265
22266            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err()
22267                && !selections.is_empty()
22268            {
22269                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
22270                // skip adding the initial selection to selection history
22271                self.selection_history.mode = SelectionHistoryMode::Skipping;
22272                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
22273                    s.select_ranges(selections.into_iter().map(|(start, end)| {
22274                        snapshot.clip_offset(start, Bias::Left)
22275                            ..snapshot.clip_offset(end, Bias::Right)
22276                    }));
22277                });
22278                self.selection_history.mode = SelectionHistoryMode::Normal;
22279            };
22280        }
22281
22282        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
22283    }
22284
22285    fn update_lsp_data(
22286        &mut self,
22287        for_buffer: Option<BufferId>,
22288        window: &mut Window,
22289        cx: &mut Context<'_, Self>,
22290    ) {
22291        self.pull_diagnostics(for_buffer, window, cx);
22292        self.refresh_colors_for_visible_range(for_buffer, window, cx);
22293    }
22294
22295    fn register_visible_buffers(&mut self, cx: &mut Context<Self>) {
22296        if self.ignore_lsp_data() {
22297            return;
22298        }
22299        for (_, (visible_buffer, _, _)) in self.visible_excerpts(cx) {
22300            self.register_buffer(visible_buffer.read(cx).remote_id(), cx);
22301        }
22302    }
22303
22304    fn register_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
22305        if self.ignore_lsp_data() {
22306            return;
22307        }
22308
22309        if !self.registered_buffers.contains_key(&buffer_id)
22310            && let Some(project) = self.project.as_ref()
22311        {
22312            if let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) {
22313                project.update(cx, |project, cx| {
22314                    self.registered_buffers.insert(
22315                        buffer_id,
22316                        project.register_buffer_with_language_servers(&buffer, cx),
22317                    );
22318                });
22319            } else {
22320                self.registered_buffers.remove(&buffer_id);
22321            }
22322        }
22323    }
22324
22325    fn ignore_lsp_data(&self) -> bool {
22326        // `ActiveDiagnostic::All` is a special mode where editor's diagnostics are managed by the external view,
22327        // skip any LSP updates for it.
22328        self.active_diagnostics == ActiveDiagnostic::All || !self.mode().is_full()
22329    }
22330}
22331
22332fn edit_for_markdown_paste<'a>(
22333    buffer: &MultiBufferSnapshot,
22334    range: Range<usize>,
22335    to_insert: &'a str,
22336    url: Option<url::Url>,
22337) -> (Range<usize>, Cow<'a, str>) {
22338    if url.is_none() {
22339        return (range, Cow::Borrowed(to_insert));
22340    };
22341
22342    let old_text = buffer.text_for_range(range.clone()).collect::<String>();
22343
22344    let new_text = if range.is_empty() || url::Url::parse(&old_text).is_ok() {
22345        Cow::Borrowed(to_insert)
22346    } else {
22347        Cow::Owned(format!("[{old_text}]({to_insert})"))
22348    };
22349    (range, new_text)
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_anchor: text::Anchor,
23205    classifier: CharClassifier,
23206    cx: &mut App,
23207) -> Task<Result<CompletionResponse>> {
23208    let languages = buffer.read(cx).languages_at(buffer_anchor);
23209    let snippet_store = project.snippets().read(cx);
23210
23211    let scopes: Vec<_> = languages
23212        .iter()
23213        .filter_map(|language| {
23214            let language_name = language.lsp_id();
23215            let snippets = snippet_store.snippets_for(Some(language_name), cx);
23216
23217            if snippets.is_empty() {
23218                None
23219            } else {
23220                Some((language.default_scope(), snippets))
23221            }
23222        })
23223        .collect();
23224
23225    if scopes.is_empty() {
23226        return Task::ready(Ok(CompletionResponse {
23227            completions: vec![],
23228            display_options: CompletionDisplayOptions::default(),
23229            is_incomplete: false,
23230        }));
23231    }
23232
23233    let snapshot = buffer.read(cx).text_snapshot();
23234    let executor = cx.background_executor().clone();
23235
23236    cx.background_spawn(async move {
23237        let is_word_char = |c| classifier.is_word(c);
23238
23239        let mut is_incomplete = false;
23240        let mut completions: Vec<Completion> = Vec::new();
23241
23242        const MAX_PREFIX_LEN: usize = 128;
23243        let buffer_offset = text::ToOffset::to_offset(&buffer_anchor, &snapshot);
23244        let window_start = buffer_offset.saturating_sub(MAX_PREFIX_LEN);
23245        let window_start = snapshot.clip_offset(window_start, Bias::Left);
23246
23247        let max_buffer_window: String = snapshot
23248            .text_for_range(window_start..buffer_offset)
23249            .collect();
23250
23251        if max_buffer_window.is_empty() {
23252            return Ok(CompletionResponse {
23253                completions: vec![],
23254                display_options: CompletionDisplayOptions::default(),
23255                is_incomplete: true,
23256            });
23257        }
23258
23259        for (_scope, snippets) in scopes.into_iter() {
23260            // Sort snippets by word count to match longer snippet prefixes first.
23261            let mut sorted_snippet_candidates = snippets
23262                .iter()
23263                .enumerate()
23264                .flat_map(|(snippet_ix, snippet)| {
23265                    snippet
23266                        .prefix
23267                        .iter()
23268                        .enumerate()
23269                        .map(move |(prefix_ix, prefix)| {
23270                            let word_count =
23271                                snippet_candidate_suffixes(prefix, is_word_char).count();
23272                            ((snippet_ix, prefix_ix), prefix, word_count)
23273                        })
23274                })
23275                .collect_vec();
23276            sorted_snippet_candidates
23277                .sort_unstable_by_key(|(_, _, word_count)| Reverse(*word_count));
23278
23279            // Each prefix may be matched multiple times; the completion menu must filter out duplicates.
23280
23281            let buffer_windows = snippet_candidate_suffixes(&max_buffer_window, is_word_char)
23282                .take(
23283                    sorted_snippet_candidates
23284                        .first()
23285                        .map(|(_, _, word_count)| *word_count)
23286                        .unwrap_or_default(),
23287                )
23288                .collect_vec();
23289
23290            const MAX_RESULTS: usize = 100;
23291            // Each match also remembers how many characters from the buffer it consumed
23292            let mut matches: Vec<(StringMatch, usize)> = vec![];
23293
23294            let mut snippet_list_cutoff_index = 0;
23295            for (buffer_index, buffer_window) in buffer_windows.iter().enumerate().rev() {
23296                let word_count = buffer_index + 1;
23297                // Increase `snippet_list_cutoff_index` until we have all of the
23298                // snippets with sufficiently many words.
23299                while sorted_snippet_candidates
23300                    .get(snippet_list_cutoff_index)
23301                    .is_some_and(|(_ix, _prefix, snippet_word_count)| {
23302                        *snippet_word_count >= word_count
23303                    })
23304                {
23305                    snippet_list_cutoff_index += 1;
23306                }
23307
23308                // Take only the candidates with at least `word_count` many words
23309                let snippet_candidates_at_word_len =
23310                    &sorted_snippet_candidates[..snippet_list_cutoff_index];
23311
23312                let candidates = snippet_candidates_at_word_len
23313                    .iter()
23314                    .map(|(_snippet_ix, prefix, _snippet_word_count)| prefix)
23315                    .enumerate() // index in `sorted_snippet_candidates`
23316                    // First char must match
23317                    .filter(|(_ix, prefix)| {
23318                        itertools::equal(
23319                            prefix
23320                                .chars()
23321                                .next()
23322                                .into_iter()
23323                                .flat_map(|c| c.to_lowercase()),
23324                            buffer_window
23325                                .chars()
23326                                .next()
23327                                .into_iter()
23328                                .flat_map(|c| c.to_lowercase()),
23329                        )
23330                    })
23331                    .map(|(ix, prefix)| StringMatchCandidate::new(ix, prefix))
23332                    .collect::<Vec<StringMatchCandidate>>();
23333
23334                matches.extend(
23335                    fuzzy::match_strings(
23336                        &candidates,
23337                        &buffer_window,
23338                        buffer_window.chars().any(|c| c.is_uppercase()),
23339                        true,
23340                        MAX_RESULTS - matches.len(), // always prioritize longer snippets
23341                        &Default::default(),
23342                        executor.clone(),
23343                    )
23344                    .await
23345                    .into_iter()
23346                    .map(|string_match| (string_match, buffer_window.len())),
23347                );
23348
23349                if matches.len() >= MAX_RESULTS {
23350                    break;
23351                }
23352            }
23353
23354            let to_lsp = |point: &text::Anchor| {
23355                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
23356                point_to_lsp(end)
23357            };
23358            let lsp_end = to_lsp(&buffer_anchor);
23359
23360            if matches.len() >= MAX_RESULTS {
23361                is_incomplete = true;
23362            }
23363
23364            completions.extend(matches.iter().map(|(string_match, buffer_window_len)| {
23365                let ((snippet_index, prefix_index), matching_prefix, _snippet_word_count) =
23366                    sorted_snippet_candidates[string_match.candidate_id];
23367                let snippet = &snippets[snippet_index];
23368                let start = buffer_offset - buffer_window_len;
23369                let start = snapshot.anchor_before(start);
23370                let range = start..buffer_anchor;
23371                let lsp_start = to_lsp(&start);
23372                let lsp_range = lsp::Range {
23373                    start: lsp_start,
23374                    end: lsp_end,
23375                };
23376                Completion {
23377                    replace_range: range,
23378                    new_text: snippet.body.clone(),
23379                    source: CompletionSource::Lsp {
23380                        insert_range: None,
23381                        server_id: LanguageServerId(usize::MAX),
23382                        resolved: true,
23383                        lsp_completion: Box::new(lsp::CompletionItem {
23384                            label: snippet.prefix.first().unwrap().clone(),
23385                            kind: Some(CompletionItemKind::SNIPPET),
23386                            label_details: snippet.description.as_ref().map(|description| {
23387                                lsp::CompletionItemLabelDetails {
23388                                    detail: Some(description.clone()),
23389                                    description: None,
23390                                }
23391                            }),
23392                            insert_text_format: Some(InsertTextFormat::SNIPPET),
23393                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
23394                                lsp::InsertReplaceEdit {
23395                                    new_text: snippet.body.clone(),
23396                                    insert: lsp_range,
23397                                    replace: lsp_range,
23398                                },
23399                            )),
23400                            filter_text: Some(snippet.body.clone()),
23401                            sort_text: Some(char::MAX.to_string()),
23402                            ..lsp::CompletionItem::default()
23403                        }),
23404                        lsp_defaults: None,
23405                    },
23406                    label: CodeLabel {
23407                        text: matching_prefix.clone(),
23408                        runs: Vec::new(),
23409                        filter_range: 0..matching_prefix.len(),
23410                    },
23411                    icon_path: None,
23412                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
23413                        single_line: snippet.name.clone().into(),
23414                        plain_text: snippet
23415                            .description
23416                            .clone()
23417                            .map(|description| description.into()),
23418                    }),
23419                    insert_text_mode: None,
23420                    confirm: None,
23421                    match_start: Some(start),
23422                    snippet_deduplication_key: Some((snippet_index, prefix_index)),
23423                }
23424            }));
23425        }
23426
23427        Ok(CompletionResponse {
23428            completions,
23429            display_options: CompletionDisplayOptions::default(),
23430            is_incomplete,
23431        })
23432    })
23433}
23434
23435impl CompletionProvider for Entity<Project> {
23436    fn completions(
23437        &self,
23438        _excerpt_id: ExcerptId,
23439        buffer: &Entity<Buffer>,
23440        buffer_position: text::Anchor,
23441        options: CompletionContext,
23442        _window: &mut Window,
23443        cx: &mut Context<Editor>,
23444    ) -> Task<Result<Vec<CompletionResponse>>> {
23445        self.update(cx, |project, cx| {
23446            let task = project.completions(buffer, buffer_position, options, cx);
23447            cx.background_spawn(task)
23448        })
23449    }
23450
23451    fn resolve_completions(
23452        &self,
23453        buffer: Entity<Buffer>,
23454        completion_indices: Vec<usize>,
23455        completions: Rc<RefCell<Box<[Completion]>>>,
23456        cx: &mut Context<Editor>,
23457    ) -> Task<Result<bool>> {
23458        self.update(cx, |project, cx| {
23459            project.lsp_store().update(cx, |lsp_store, cx| {
23460                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
23461            })
23462        })
23463    }
23464
23465    fn apply_additional_edits_for_completion(
23466        &self,
23467        buffer: Entity<Buffer>,
23468        completions: Rc<RefCell<Box<[Completion]>>>,
23469        completion_index: usize,
23470        push_to_history: bool,
23471        cx: &mut Context<Editor>,
23472    ) -> Task<Result<Option<language::Transaction>>> {
23473        self.update(cx, |project, cx| {
23474            project.lsp_store().update(cx, |lsp_store, cx| {
23475                lsp_store.apply_additional_edits_for_completion(
23476                    buffer,
23477                    completions,
23478                    completion_index,
23479                    push_to_history,
23480                    cx,
23481                )
23482            })
23483        })
23484    }
23485
23486    fn is_completion_trigger(
23487        &self,
23488        buffer: &Entity<Buffer>,
23489        position: language::Anchor,
23490        text: &str,
23491        trigger_in_words: bool,
23492        menu_is_open: bool,
23493        cx: &mut Context<Editor>,
23494    ) -> bool {
23495        let mut chars = text.chars();
23496        let char = if let Some(char) = chars.next() {
23497            char
23498        } else {
23499            return false;
23500        };
23501        if chars.next().is_some() {
23502            return false;
23503        }
23504
23505        let buffer = buffer.read(cx);
23506        let snapshot = buffer.snapshot();
23507        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
23508            return false;
23509        }
23510        let classifier = snapshot
23511            .char_classifier_at(position)
23512            .scope_context(Some(CharScopeContext::Completion));
23513        if trigger_in_words && classifier.is_word(char) {
23514            return true;
23515        }
23516
23517        buffer.completion_triggers().contains(text)
23518    }
23519
23520    fn show_snippets(&self) -> bool {
23521        true
23522    }
23523}
23524
23525impl SemanticsProvider for Entity<Project> {
23526    fn hover(
23527        &self,
23528        buffer: &Entity<Buffer>,
23529        position: text::Anchor,
23530        cx: &mut App,
23531    ) -> Option<Task<Option<Vec<project::Hover>>>> {
23532        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
23533    }
23534
23535    fn document_highlights(
23536        &self,
23537        buffer: &Entity<Buffer>,
23538        position: text::Anchor,
23539        cx: &mut App,
23540    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
23541        Some(self.update(cx, |project, cx| {
23542            project.document_highlights(buffer, position, cx)
23543        }))
23544    }
23545
23546    fn definitions(
23547        &self,
23548        buffer: &Entity<Buffer>,
23549        position: text::Anchor,
23550        kind: GotoDefinitionKind,
23551        cx: &mut App,
23552    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>> {
23553        Some(self.update(cx, |project, cx| match kind {
23554            GotoDefinitionKind::Symbol => project.definitions(buffer, position, cx),
23555            GotoDefinitionKind::Declaration => project.declarations(buffer, position, cx),
23556            GotoDefinitionKind::Type => project.type_definitions(buffer, position, cx),
23557            GotoDefinitionKind::Implementation => project.implementations(buffer, position, cx),
23558        }))
23559    }
23560
23561    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
23562        self.update(cx, |project, cx| {
23563            if project
23564                .active_debug_session(cx)
23565                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
23566            {
23567                return true;
23568            }
23569
23570            buffer.update(cx, |buffer, cx| {
23571                project.any_language_server_supports_inlay_hints(buffer, cx)
23572            })
23573        })
23574    }
23575
23576    fn inline_values(
23577        &self,
23578        buffer_handle: Entity<Buffer>,
23579        range: Range<text::Anchor>,
23580        cx: &mut App,
23581    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
23582        self.update(cx, |project, cx| {
23583            let (session, active_stack_frame) = project.active_debug_session(cx)?;
23584
23585            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
23586        })
23587    }
23588
23589    fn applicable_inlay_chunks(
23590        &self,
23591        buffer: &Entity<Buffer>,
23592        ranges: &[Range<text::Anchor>],
23593        cx: &mut App,
23594    ) -> Vec<Range<BufferRow>> {
23595        self.read(cx).lsp_store().update(cx, |lsp_store, cx| {
23596            lsp_store.applicable_inlay_chunks(buffer, ranges, cx)
23597        })
23598    }
23599
23600    fn invalidate_inlay_hints(&self, for_buffers: &HashSet<BufferId>, cx: &mut App) {
23601        self.read(cx).lsp_store().update(cx, |lsp_store, _| {
23602            lsp_store.invalidate_inlay_hints(for_buffers)
23603        });
23604    }
23605
23606    fn inlay_hints(
23607        &self,
23608        invalidate: InvalidationStrategy,
23609        buffer: Entity<Buffer>,
23610        ranges: Vec<Range<text::Anchor>>,
23611        known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
23612        cx: &mut App,
23613    ) -> Option<HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>>> {
23614        Some(self.read(cx).lsp_store().update(cx, |lsp_store, cx| {
23615            lsp_store.inlay_hints(invalidate, buffer, ranges, known_chunks, cx)
23616        }))
23617    }
23618
23619    fn range_for_rename(
23620        &self,
23621        buffer: &Entity<Buffer>,
23622        position: text::Anchor,
23623        cx: &mut App,
23624    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
23625        Some(self.update(cx, |project, cx| {
23626            let buffer = buffer.clone();
23627            let task = project.prepare_rename(buffer.clone(), position, cx);
23628            cx.spawn(async move |_, cx| {
23629                Ok(match task.await? {
23630                    PrepareRenameResponse::Success(range) => Some(range),
23631                    PrepareRenameResponse::InvalidPosition => None,
23632                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
23633                        // Fallback on using TreeSitter info to determine identifier range
23634                        buffer.read_with(cx, |buffer, _| {
23635                            let snapshot = buffer.snapshot();
23636                            let (range, kind) = snapshot.surrounding_word(position, None);
23637                            if kind != Some(CharKind::Word) {
23638                                return None;
23639                            }
23640                            Some(
23641                                snapshot.anchor_before(range.start)
23642                                    ..snapshot.anchor_after(range.end),
23643                            )
23644                        })?
23645                    }
23646                })
23647            })
23648        }))
23649    }
23650
23651    fn perform_rename(
23652        &self,
23653        buffer: &Entity<Buffer>,
23654        position: text::Anchor,
23655        new_name: String,
23656        cx: &mut App,
23657    ) -> Option<Task<Result<ProjectTransaction>>> {
23658        Some(self.update(cx, |project, cx| {
23659            project.perform_rename(buffer.clone(), position, new_name, cx)
23660        }))
23661    }
23662}
23663
23664fn consume_contiguous_rows(
23665    contiguous_row_selections: &mut Vec<Selection<Point>>,
23666    selection: &Selection<Point>,
23667    display_map: &DisplaySnapshot,
23668    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
23669) -> (MultiBufferRow, MultiBufferRow) {
23670    contiguous_row_selections.push(selection.clone());
23671    let start_row = starting_row(selection, display_map);
23672    let mut end_row = ending_row(selection, display_map);
23673
23674    while let Some(next_selection) = selections.peek() {
23675        if next_selection.start.row <= end_row.0 {
23676            end_row = ending_row(next_selection, display_map);
23677            contiguous_row_selections.push(selections.next().unwrap().clone());
23678        } else {
23679            break;
23680        }
23681    }
23682    (start_row, end_row)
23683}
23684
23685fn starting_row(selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
23686    if selection.start.column > 0 {
23687        MultiBufferRow(display_map.prev_line_boundary(selection.start).0.row)
23688    } else {
23689        MultiBufferRow(selection.start.row)
23690    }
23691}
23692
23693fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
23694    if next_selection.end.column > 0 || next_selection.is_empty() {
23695        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
23696    } else {
23697        MultiBufferRow(next_selection.end.row)
23698    }
23699}
23700
23701impl EditorSnapshot {
23702    pub fn remote_selections_in_range<'a>(
23703        &'a self,
23704        range: &'a Range<Anchor>,
23705        collaboration_hub: &dyn CollaborationHub,
23706        cx: &'a App,
23707    ) -> impl 'a + Iterator<Item = RemoteSelection> {
23708        let participant_names = collaboration_hub.user_names(cx);
23709        let participant_indices = collaboration_hub.user_participant_indices(cx);
23710        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
23711        let collaborators_by_replica_id = collaborators_by_peer_id
23712            .values()
23713            .map(|collaborator| (collaborator.replica_id, collaborator))
23714            .collect::<HashMap<_, _>>();
23715        self.buffer_snapshot()
23716            .selections_in_range(range, false)
23717            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
23718                if replica_id == ReplicaId::AGENT {
23719                    Some(RemoteSelection {
23720                        replica_id,
23721                        selection,
23722                        cursor_shape,
23723                        line_mode,
23724                        collaborator_id: CollaboratorId::Agent,
23725                        user_name: Some("Agent".into()),
23726                        color: cx.theme().players().agent(),
23727                    })
23728                } else {
23729                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
23730                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
23731                    let user_name = participant_names.get(&collaborator.user_id).cloned();
23732                    Some(RemoteSelection {
23733                        replica_id,
23734                        selection,
23735                        cursor_shape,
23736                        line_mode,
23737                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
23738                        user_name,
23739                        color: if let Some(index) = participant_index {
23740                            cx.theme().players().color_for_participant(index.0)
23741                        } else {
23742                            cx.theme().players().absent()
23743                        },
23744                    })
23745                }
23746            })
23747    }
23748
23749    pub fn hunks_for_ranges(
23750        &self,
23751        ranges: impl IntoIterator<Item = Range<Point>>,
23752    ) -> Vec<MultiBufferDiffHunk> {
23753        let mut hunks = Vec::new();
23754        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
23755            HashMap::default();
23756        for query_range in ranges {
23757            let query_rows =
23758                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
23759            for hunk in self.buffer_snapshot().diff_hunks_in_range(
23760                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
23761            ) {
23762                // Include deleted hunks that are adjacent to the query range, because
23763                // otherwise they would be missed.
23764                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
23765                if hunk.status().is_deleted() {
23766                    intersects_range |= hunk.row_range.start == query_rows.end;
23767                    intersects_range |= hunk.row_range.end == query_rows.start;
23768                }
23769                if intersects_range {
23770                    if !processed_buffer_rows
23771                        .entry(hunk.buffer_id)
23772                        .or_default()
23773                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
23774                    {
23775                        continue;
23776                    }
23777                    hunks.push(hunk);
23778                }
23779            }
23780        }
23781
23782        hunks
23783    }
23784
23785    fn display_diff_hunks_for_rows<'a>(
23786        &'a self,
23787        display_rows: Range<DisplayRow>,
23788        folded_buffers: &'a HashSet<BufferId>,
23789    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
23790        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
23791        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
23792
23793        self.buffer_snapshot()
23794            .diff_hunks_in_range(buffer_start..buffer_end)
23795            .filter_map(|hunk| {
23796                if folded_buffers.contains(&hunk.buffer_id) {
23797                    return None;
23798                }
23799
23800                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
23801                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
23802
23803                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
23804                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
23805
23806                let display_hunk = if hunk_display_start.column() != 0 {
23807                    DisplayDiffHunk::Folded {
23808                        display_row: hunk_display_start.row(),
23809                    }
23810                } else {
23811                    let mut end_row = hunk_display_end.row();
23812                    if hunk_display_end.column() > 0 {
23813                        end_row.0 += 1;
23814                    }
23815                    let is_created_file = hunk.is_created_file();
23816                    DisplayDiffHunk::Unfolded {
23817                        status: hunk.status(),
23818                        diff_base_byte_range: hunk.diff_base_byte_range,
23819                        display_row_range: hunk_display_start.row()..end_row,
23820                        multi_buffer_range: Anchor::range_in_buffer(
23821                            hunk.excerpt_id,
23822                            hunk.buffer_id,
23823                            hunk.buffer_range,
23824                        ),
23825                        is_created_file,
23826                    }
23827                };
23828
23829                Some(display_hunk)
23830            })
23831    }
23832
23833    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
23834        self.display_snapshot
23835            .buffer_snapshot()
23836            .language_at(position)
23837    }
23838
23839    pub fn is_focused(&self) -> bool {
23840        self.is_focused
23841    }
23842
23843    pub fn placeholder_text(&self) -> Option<String> {
23844        self.placeholder_display_snapshot
23845            .as_ref()
23846            .map(|display_map| display_map.text())
23847    }
23848
23849    pub fn scroll_position(&self) -> gpui::Point<ScrollOffset> {
23850        self.scroll_anchor.scroll_position(&self.display_snapshot)
23851    }
23852
23853    fn gutter_dimensions(
23854        &self,
23855        font_id: FontId,
23856        font_size: Pixels,
23857        max_line_number_width: Pixels,
23858        cx: &App,
23859    ) -> Option<GutterDimensions> {
23860        if !self.show_gutter {
23861            return None;
23862        }
23863
23864        let ch_width = cx.text_system().ch_width(font_id, font_size).log_err()?;
23865        let ch_advance = cx.text_system().ch_advance(font_id, font_size).log_err()?;
23866
23867        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
23868            matches!(
23869                ProjectSettings::get_global(cx).git.git_gutter,
23870                GitGutterSetting::TrackedFiles
23871            )
23872        });
23873        let gutter_settings = EditorSettings::get_global(cx).gutter;
23874        let show_line_numbers = self
23875            .show_line_numbers
23876            .unwrap_or(gutter_settings.line_numbers);
23877        let line_gutter_width = if show_line_numbers {
23878            // Avoid flicker-like gutter resizes when the line number gains another digit by
23879            // only resizing the gutter on files with > 10**min_line_number_digits lines.
23880            let min_width_for_number_on_gutter =
23881                ch_advance * gutter_settings.min_line_number_digits as f32;
23882            max_line_number_width.max(min_width_for_number_on_gutter)
23883        } else {
23884            0.0.into()
23885        };
23886
23887        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
23888        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
23889
23890        let git_blame_entries_width =
23891            self.git_blame_gutter_max_author_length
23892                .map(|max_author_length| {
23893                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
23894                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
23895
23896                    /// The number of characters to dedicate to gaps and margins.
23897                    const SPACING_WIDTH: usize = 4;
23898
23899                    let max_char_count = max_author_length.min(renderer.max_author_length())
23900                        + ::git::SHORT_SHA_LENGTH
23901                        + MAX_RELATIVE_TIMESTAMP.len()
23902                        + SPACING_WIDTH;
23903
23904                    ch_advance * max_char_count
23905                });
23906
23907        let is_singleton = self.buffer_snapshot().is_singleton();
23908
23909        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
23910        left_padding += if !is_singleton {
23911            ch_width * 4.0
23912        } else if show_runnables || show_breakpoints {
23913            ch_width * 3.0
23914        } else if show_git_gutter && show_line_numbers {
23915            ch_width * 2.0
23916        } else if show_git_gutter || show_line_numbers {
23917            ch_width
23918        } else {
23919            px(0.)
23920        };
23921
23922        let shows_folds = is_singleton && gutter_settings.folds;
23923
23924        let right_padding = if shows_folds && show_line_numbers {
23925            ch_width * 4.0
23926        } else if shows_folds || (!is_singleton && show_line_numbers) {
23927            ch_width * 3.0
23928        } else if show_line_numbers {
23929            ch_width
23930        } else {
23931            px(0.)
23932        };
23933
23934        Some(GutterDimensions {
23935            left_padding,
23936            right_padding,
23937            width: line_gutter_width + left_padding + right_padding,
23938            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
23939            git_blame_entries_width,
23940        })
23941    }
23942
23943    pub fn render_crease_toggle(
23944        &self,
23945        buffer_row: MultiBufferRow,
23946        row_contains_cursor: bool,
23947        editor: Entity<Editor>,
23948        window: &mut Window,
23949        cx: &mut App,
23950    ) -> Option<AnyElement> {
23951        let folded = self.is_line_folded(buffer_row);
23952        let mut is_foldable = false;
23953
23954        if let Some(crease) = self
23955            .crease_snapshot
23956            .query_row(buffer_row, self.buffer_snapshot())
23957        {
23958            is_foldable = true;
23959            match crease {
23960                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
23961                    if let Some(render_toggle) = render_toggle {
23962                        let toggle_callback =
23963                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
23964                                if folded {
23965                                    editor.update(cx, |editor, cx| {
23966                                        editor.fold_at(buffer_row, window, cx)
23967                                    });
23968                                } else {
23969                                    editor.update(cx, |editor, cx| {
23970                                        editor.unfold_at(buffer_row, window, cx)
23971                                    });
23972                                }
23973                            });
23974                        return Some((render_toggle)(
23975                            buffer_row,
23976                            folded,
23977                            toggle_callback,
23978                            window,
23979                            cx,
23980                        ));
23981                    }
23982                }
23983            }
23984        }
23985
23986        is_foldable |= self.starts_indent(buffer_row);
23987
23988        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
23989            Some(
23990                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
23991                    .toggle_state(folded)
23992                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
23993                        if folded {
23994                            this.unfold_at(buffer_row, window, cx);
23995                        } else {
23996                            this.fold_at(buffer_row, window, cx);
23997                        }
23998                    }))
23999                    .into_any_element(),
24000            )
24001        } else {
24002            None
24003        }
24004    }
24005
24006    pub fn render_crease_trailer(
24007        &self,
24008        buffer_row: MultiBufferRow,
24009        window: &mut Window,
24010        cx: &mut App,
24011    ) -> Option<AnyElement> {
24012        let folded = self.is_line_folded(buffer_row);
24013        if let Crease::Inline { render_trailer, .. } = self
24014            .crease_snapshot
24015            .query_row(buffer_row, self.buffer_snapshot())?
24016        {
24017            let render_trailer = render_trailer.as_ref()?;
24018            Some(render_trailer(buffer_row, folded, window, cx))
24019        } else {
24020            None
24021        }
24022    }
24023}
24024
24025impl Deref for EditorSnapshot {
24026    type Target = DisplaySnapshot;
24027
24028    fn deref(&self) -> &Self::Target {
24029        &self.display_snapshot
24030    }
24031}
24032
24033#[derive(Clone, Debug, PartialEq, Eq)]
24034pub enum EditorEvent {
24035    InputIgnored {
24036        text: Arc<str>,
24037    },
24038    InputHandled {
24039        utf16_range_to_replace: Option<Range<isize>>,
24040        text: Arc<str>,
24041    },
24042    ExcerptsAdded {
24043        buffer: Entity<Buffer>,
24044        predecessor: ExcerptId,
24045        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
24046    },
24047    ExcerptsRemoved {
24048        ids: Vec<ExcerptId>,
24049        removed_buffer_ids: Vec<BufferId>,
24050    },
24051    BufferFoldToggled {
24052        ids: Vec<ExcerptId>,
24053        folded: bool,
24054    },
24055    ExcerptsEdited {
24056        ids: Vec<ExcerptId>,
24057    },
24058    ExcerptsExpanded {
24059        ids: Vec<ExcerptId>,
24060    },
24061    BufferEdited,
24062    Edited {
24063        transaction_id: clock::Lamport,
24064    },
24065    Reparsed(BufferId),
24066    Focused,
24067    FocusedIn,
24068    Blurred,
24069    DirtyChanged,
24070    Saved,
24071    TitleChanged,
24072    SelectionsChanged {
24073        local: bool,
24074    },
24075    ScrollPositionChanged {
24076        local: bool,
24077        autoscroll: bool,
24078    },
24079    TransactionUndone {
24080        transaction_id: clock::Lamport,
24081    },
24082    TransactionBegun {
24083        transaction_id: clock::Lamport,
24084    },
24085    CursorShapeChanged,
24086    BreadcrumbsChanged,
24087    PushedToNavHistory {
24088        anchor: Anchor,
24089        is_deactivate: bool,
24090    },
24091}
24092
24093impl EventEmitter<EditorEvent> for Editor {}
24094
24095impl Focusable for Editor {
24096    fn focus_handle(&self, _cx: &App) -> FocusHandle {
24097        self.focus_handle.clone()
24098    }
24099}
24100
24101impl Render for Editor {
24102    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
24103        let settings = ThemeSettings::get_global(cx);
24104
24105        let mut text_style = match self.mode {
24106            EditorMode::SingleLine | EditorMode::AutoHeight { .. } => TextStyle {
24107                color: cx.theme().colors().editor_foreground,
24108                font_family: settings.ui_font.family.clone(),
24109                font_features: settings.ui_font.features.clone(),
24110                font_fallbacks: settings.ui_font.fallbacks.clone(),
24111                font_size: rems(0.875).into(),
24112                font_weight: settings.ui_font.weight,
24113                line_height: relative(settings.buffer_line_height.value()),
24114                ..Default::default()
24115            },
24116            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
24117                color: cx.theme().colors().editor_foreground,
24118                font_family: settings.buffer_font.family.clone(),
24119                font_features: settings.buffer_font.features.clone(),
24120                font_fallbacks: settings.buffer_font.fallbacks.clone(),
24121                font_size: settings.buffer_font_size(cx).into(),
24122                font_weight: settings.buffer_font.weight,
24123                line_height: relative(settings.buffer_line_height.value()),
24124                ..Default::default()
24125            },
24126        };
24127        if let Some(text_style_refinement) = &self.text_style_refinement {
24128            text_style.refine(text_style_refinement)
24129        }
24130
24131        let background = match self.mode {
24132            EditorMode::SingleLine => cx.theme().system().transparent,
24133            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
24134            EditorMode::Full { .. } => cx.theme().colors().editor_background,
24135            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
24136        };
24137
24138        EditorElement::new(
24139            &cx.entity(),
24140            EditorStyle {
24141                background,
24142                border: cx.theme().colors().border,
24143                local_player: cx.theme().players().local(),
24144                text: text_style,
24145                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
24146                syntax: cx.theme().syntax().clone(),
24147                status: cx.theme().status().clone(),
24148                inlay_hints_style: make_inlay_hints_style(cx),
24149                edit_prediction_styles: make_suggestion_styles(cx),
24150                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
24151                show_underlines: self.diagnostics_enabled(),
24152            },
24153        )
24154    }
24155}
24156
24157impl EntityInputHandler for Editor {
24158    fn text_for_range(
24159        &mut self,
24160        range_utf16: Range<usize>,
24161        adjusted_range: &mut Option<Range<usize>>,
24162        _: &mut Window,
24163        cx: &mut Context<Self>,
24164    ) -> Option<String> {
24165        let snapshot = self.buffer.read(cx).read(cx);
24166        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
24167        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
24168        if (start.0..end.0) != range_utf16 {
24169            adjusted_range.replace(start.0..end.0);
24170        }
24171        Some(snapshot.text_for_range(start..end).collect())
24172    }
24173
24174    fn selected_text_range(
24175        &mut self,
24176        ignore_disabled_input: bool,
24177        _: &mut Window,
24178        cx: &mut Context<Self>,
24179    ) -> Option<UTF16Selection> {
24180        // Prevent the IME menu from appearing when holding down an alphabetic key
24181        // while input is disabled.
24182        if !ignore_disabled_input && !self.input_enabled {
24183            return None;
24184        }
24185
24186        let selection = self
24187            .selections
24188            .newest::<OffsetUtf16>(&self.display_snapshot(cx));
24189        let range = selection.range();
24190
24191        Some(UTF16Selection {
24192            range: range.start.0..range.end.0,
24193            reversed: selection.reversed,
24194        })
24195    }
24196
24197    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
24198        let snapshot = self.buffer.read(cx).read(cx);
24199        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
24200        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
24201    }
24202
24203    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
24204        self.clear_highlights::<InputComposition>(cx);
24205        self.ime_transaction.take();
24206    }
24207
24208    fn replace_text_in_range(
24209        &mut self,
24210        range_utf16: Option<Range<usize>>,
24211        text: &str,
24212        window: &mut Window,
24213        cx: &mut Context<Self>,
24214    ) {
24215        if !self.input_enabled {
24216            cx.emit(EditorEvent::InputIgnored { text: text.into() });
24217            return;
24218        }
24219
24220        self.transact(window, cx, |this, window, cx| {
24221            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
24222                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
24223                Some(this.selection_replacement_ranges(range_utf16, cx))
24224            } else {
24225                this.marked_text_ranges(cx)
24226            };
24227
24228            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
24229                let newest_selection_id = this.selections.newest_anchor().id;
24230                this.selections
24231                    .all::<OffsetUtf16>(&this.display_snapshot(cx))
24232                    .iter()
24233                    .zip(ranges_to_replace.iter())
24234                    .find_map(|(selection, range)| {
24235                        if selection.id == newest_selection_id {
24236                            Some(
24237                                (range.start.0 as isize - selection.head().0 as isize)
24238                                    ..(range.end.0 as isize - selection.head().0 as isize),
24239                            )
24240                        } else {
24241                            None
24242                        }
24243                    })
24244            });
24245
24246            cx.emit(EditorEvent::InputHandled {
24247                utf16_range_to_replace: range_to_replace,
24248                text: text.into(),
24249            });
24250
24251            if let Some(new_selected_ranges) = new_selected_ranges {
24252                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
24253                    selections.select_ranges(new_selected_ranges)
24254                });
24255                this.backspace(&Default::default(), window, cx);
24256            }
24257
24258            this.handle_input(text, window, cx);
24259        });
24260
24261        if let Some(transaction) = self.ime_transaction {
24262            self.buffer.update(cx, |buffer, cx| {
24263                buffer.group_until_transaction(transaction, cx);
24264            });
24265        }
24266
24267        self.unmark_text(window, cx);
24268    }
24269
24270    fn replace_and_mark_text_in_range(
24271        &mut self,
24272        range_utf16: Option<Range<usize>>,
24273        text: &str,
24274        new_selected_range_utf16: Option<Range<usize>>,
24275        window: &mut Window,
24276        cx: &mut Context<Self>,
24277    ) {
24278        if !self.input_enabled {
24279            return;
24280        }
24281
24282        let transaction = self.transact(window, cx, |this, window, cx| {
24283            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
24284                let snapshot = this.buffer.read(cx).read(cx);
24285                if let Some(relative_range_utf16) = range_utf16.as_ref() {
24286                    for marked_range in &mut marked_ranges {
24287                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
24288                        marked_range.start.0 += relative_range_utf16.start;
24289                        marked_range.start =
24290                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
24291                        marked_range.end =
24292                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
24293                    }
24294                }
24295                Some(marked_ranges)
24296            } else if let Some(range_utf16) = range_utf16 {
24297                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
24298                Some(this.selection_replacement_ranges(range_utf16, cx))
24299            } else {
24300                None
24301            };
24302
24303            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
24304                let newest_selection_id = this.selections.newest_anchor().id;
24305                this.selections
24306                    .all::<OffsetUtf16>(&this.display_snapshot(cx))
24307                    .iter()
24308                    .zip(ranges_to_replace.iter())
24309                    .find_map(|(selection, range)| {
24310                        if selection.id == newest_selection_id {
24311                            Some(
24312                                (range.start.0 as isize - selection.head().0 as isize)
24313                                    ..(range.end.0 as isize - selection.head().0 as isize),
24314                            )
24315                        } else {
24316                            None
24317                        }
24318                    })
24319            });
24320
24321            cx.emit(EditorEvent::InputHandled {
24322                utf16_range_to_replace: range_to_replace,
24323                text: text.into(),
24324            });
24325
24326            if let Some(ranges) = ranges_to_replace {
24327                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
24328                    s.select_ranges(ranges)
24329                });
24330            }
24331
24332            let marked_ranges = {
24333                let snapshot = this.buffer.read(cx).read(cx);
24334                this.selections
24335                    .disjoint_anchors_arc()
24336                    .iter()
24337                    .map(|selection| {
24338                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
24339                    })
24340                    .collect::<Vec<_>>()
24341            };
24342
24343            if text.is_empty() {
24344                this.unmark_text(window, cx);
24345            } else {
24346                this.highlight_text::<InputComposition>(
24347                    marked_ranges.clone(),
24348                    HighlightStyle {
24349                        underline: Some(UnderlineStyle {
24350                            thickness: px(1.),
24351                            color: None,
24352                            wavy: false,
24353                        }),
24354                        ..Default::default()
24355                    },
24356                    cx,
24357                );
24358            }
24359
24360            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
24361            let use_autoclose = this.use_autoclose;
24362            let use_auto_surround = this.use_auto_surround;
24363            this.set_use_autoclose(false);
24364            this.set_use_auto_surround(false);
24365            this.handle_input(text, window, cx);
24366            this.set_use_autoclose(use_autoclose);
24367            this.set_use_auto_surround(use_auto_surround);
24368
24369            if let Some(new_selected_range) = new_selected_range_utf16 {
24370                let snapshot = this.buffer.read(cx).read(cx);
24371                let new_selected_ranges = marked_ranges
24372                    .into_iter()
24373                    .map(|marked_range| {
24374                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
24375                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
24376                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
24377                        snapshot.clip_offset_utf16(new_start, Bias::Left)
24378                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
24379                    })
24380                    .collect::<Vec<_>>();
24381
24382                drop(snapshot);
24383                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
24384                    selections.select_ranges(new_selected_ranges)
24385                });
24386            }
24387        });
24388
24389        self.ime_transaction = self.ime_transaction.or(transaction);
24390        if let Some(transaction) = self.ime_transaction {
24391            self.buffer.update(cx, |buffer, cx| {
24392                buffer.group_until_transaction(transaction, cx);
24393            });
24394        }
24395
24396        if self.text_highlights::<InputComposition>(cx).is_none() {
24397            self.ime_transaction.take();
24398        }
24399    }
24400
24401    fn bounds_for_range(
24402        &mut self,
24403        range_utf16: Range<usize>,
24404        element_bounds: gpui::Bounds<Pixels>,
24405        window: &mut Window,
24406        cx: &mut Context<Self>,
24407    ) -> Option<gpui::Bounds<Pixels>> {
24408        let text_layout_details = self.text_layout_details(window);
24409        let CharacterDimensions {
24410            em_width,
24411            em_advance,
24412            line_height,
24413        } = self.character_dimensions(window);
24414
24415        let snapshot = self.snapshot(window, cx);
24416        let scroll_position = snapshot.scroll_position();
24417        let scroll_left = scroll_position.x * ScrollOffset::from(em_advance);
24418
24419        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
24420        let x = Pixels::from(
24421            ScrollOffset::from(
24422                snapshot.x_for_display_point(start, &text_layout_details)
24423                    + self.gutter_dimensions.full_width(),
24424            ) - scroll_left,
24425        );
24426        let y = line_height * (start.row().as_f64() - scroll_position.y) as f32;
24427
24428        Some(Bounds {
24429            origin: element_bounds.origin + point(x, y),
24430            size: size(em_width, line_height),
24431        })
24432    }
24433
24434    fn character_index_for_point(
24435        &mut self,
24436        point: gpui::Point<Pixels>,
24437        _window: &mut Window,
24438        _cx: &mut Context<Self>,
24439    ) -> Option<usize> {
24440        let position_map = self.last_position_map.as_ref()?;
24441        if !position_map.text_hitbox.contains(&point) {
24442            return None;
24443        }
24444        let display_point = position_map.point_for_position(point).previous_valid;
24445        let anchor = position_map
24446            .snapshot
24447            .display_point_to_anchor(display_point, Bias::Left);
24448        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot());
24449        Some(utf16_offset.0)
24450    }
24451
24452    fn accepts_text_input(&self, _window: &mut Window, _cx: &mut Context<Self>) -> bool {
24453        self.input_enabled
24454    }
24455}
24456
24457trait SelectionExt {
24458    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
24459    fn spanned_rows(
24460        &self,
24461        include_end_if_at_line_start: bool,
24462        map: &DisplaySnapshot,
24463    ) -> Range<MultiBufferRow>;
24464}
24465
24466impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
24467    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
24468        let start = self
24469            .start
24470            .to_point(map.buffer_snapshot())
24471            .to_display_point(map);
24472        let end = self
24473            .end
24474            .to_point(map.buffer_snapshot())
24475            .to_display_point(map);
24476        if self.reversed {
24477            end..start
24478        } else {
24479            start..end
24480        }
24481    }
24482
24483    fn spanned_rows(
24484        &self,
24485        include_end_if_at_line_start: bool,
24486        map: &DisplaySnapshot,
24487    ) -> Range<MultiBufferRow> {
24488        let start = self.start.to_point(map.buffer_snapshot());
24489        let mut end = self.end.to_point(map.buffer_snapshot());
24490        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
24491            end.row -= 1;
24492        }
24493
24494        let buffer_start = map.prev_line_boundary(start).0;
24495        let buffer_end = map.next_line_boundary(end).0;
24496        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
24497    }
24498}
24499
24500impl<T: InvalidationRegion> InvalidationStack<T> {
24501    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
24502    where
24503        S: Clone + ToOffset,
24504    {
24505        while let Some(region) = self.last() {
24506            let all_selections_inside_invalidation_ranges =
24507                if selections.len() == region.ranges().len() {
24508                    selections
24509                        .iter()
24510                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
24511                        .all(|(selection, invalidation_range)| {
24512                            let head = selection.head().to_offset(buffer);
24513                            invalidation_range.start <= head && invalidation_range.end >= head
24514                        })
24515                } else {
24516                    false
24517                };
24518
24519            if all_selections_inside_invalidation_ranges {
24520                break;
24521            } else {
24522                self.pop();
24523            }
24524        }
24525    }
24526}
24527
24528impl<T> Default for InvalidationStack<T> {
24529    fn default() -> Self {
24530        Self(Default::default())
24531    }
24532}
24533
24534impl<T> Deref for InvalidationStack<T> {
24535    type Target = Vec<T>;
24536
24537    fn deref(&self) -> &Self::Target {
24538        &self.0
24539    }
24540}
24541
24542impl<T> DerefMut for InvalidationStack<T> {
24543    fn deref_mut(&mut self) -> &mut Self::Target {
24544        &mut self.0
24545    }
24546}
24547
24548impl InvalidationRegion for SnippetState {
24549    fn ranges(&self) -> &[Range<Anchor>] {
24550        &self.ranges[self.active_index]
24551    }
24552}
24553
24554fn edit_prediction_edit_text(
24555    current_snapshot: &BufferSnapshot,
24556    edits: &[(Range<Anchor>, impl AsRef<str>)],
24557    edit_preview: &EditPreview,
24558    include_deletions: bool,
24559    cx: &App,
24560) -> HighlightedText {
24561    let edits = edits
24562        .iter()
24563        .map(|(anchor, text)| (anchor.start.text_anchor..anchor.end.text_anchor, text))
24564        .collect::<Vec<_>>();
24565
24566    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
24567}
24568
24569fn edit_prediction_fallback_text(edits: &[(Range<Anchor>, Arc<str>)], cx: &App) -> HighlightedText {
24570    // Fallback for providers that don't provide edit_preview (like Copilot/Supermaven)
24571    // Just show the raw edit text with basic styling
24572    let mut text = String::new();
24573    let mut highlights = Vec::new();
24574
24575    let insertion_highlight_style = HighlightStyle {
24576        color: Some(cx.theme().colors().text),
24577        ..Default::default()
24578    };
24579
24580    for (_, edit_text) in edits {
24581        let start_offset = text.len();
24582        text.push_str(edit_text);
24583        let end_offset = text.len();
24584
24585        if start_offset < end_offset {
24586            highlights.push((start_offset..end_offset, insertion_highlight_style));
24587        }
24588    }
24589
24590    HighlightedText {
24591        text: text.into(),
24592        highlights,
24593    }
24594}
24595
24596pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
24597    match severity {
24598        lsp::DiagnosticSeverity::ERROR => colors.error,
24599        lsp::DiagnosticSeverity::WARNING => colors.warning,
24600        lsp::DiagnosticSeverity::INFORMATION => colors.info,
24601        lsp::DiagnosticSeverity::HINT => colors.info,
24602        _ => colors.ignored,
24603    }
24604}
24605
24606pub fn styled_runs_for_code_label<'a>(
24607    label: &'a CodeLabel,
24608    syntax_theme: &'a theme::SyntaxTheme,
24609) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
24610    let fade_out = HighlightStyle {
24611        fade_out: Some(0.35),
24612        ..Default::default()
24613    };
24614
24615    let mut prev_end = label.filter_range.end;
24616    label
24617        .runs
24618        .iter()
24619        .enumerate()
24620        .flat_map(move |(ix, (range, highlight_id))| {
24621            let style = if let Some(style) = highlight_id.style(syntax_theme) {
24622                style
24623            } else {
24624                return Default::default();
24625            };
24626            let muted_style = style.highlight(fade_out);
24627
24628            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
24629            if range.start >= label.filter_range.end {
24630                if range.start > prev_end {
24631                    runs.push((prev_end..range.start, fade_out));
24632                }
24633                runs.push((range.clone(), muted_style));
24634            } else if range.end <= label.filter_range.end {
24635                runs.push((range.clone(), style));
24636            } else {
24637                runs.push((range.start..label.filter_range.end, style));
24638                runs.push((label.filter_range.end..range.end, muted_style));
24639            }
24640            prev_end = cmp::max(prev_end, range.end);
24641
24642            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
24643                runs.push((prev_end..label.text.len(), fade_out));
24644            }
24645
24646            runs
24647        })
24648}
24649
24650pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
24651    let mut prev_index = 0;
24652    let mut prev_codepoint: Option<char> = None;
24653    text.char_indices()
24654        .chain([(text.len(), '\0')])
24655        .filter_map(move |(index, codepoint)| {
24656            let prev_codepoint = prev_codepoint.replace(codepoint)?;
24657            let is_boundary = index == text.len()
24658                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
24659                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
24660            if is_boundary {
24661                let chunk = &text[prev_index..index];
24662                prev_index = index;
24663                Some(chunk)
24664            } else {
24665                None
24666            }
24667        })
24668}
24669
24670/// Given a string of text immediately before the cursor, iterates over possible
24671/// strings a snippet could match to. More precisely: returns an iterator over
24672/// suffixes of `text` created by splitting at word boundaries (before & after
24673/// every non-word character).
24674///
24675/// Shorter suffixes are returned first.
24676pub(crate) fn snippet_candidate_suffixes(
24677    text: &str,
24678    is_word_char: impl Fn(char) -> bool,
24679) -> impl std::iter::Iterator<Item = &str> {
24680    let mut prev_index = text.len();
24681    let mut prev_codepoint = None;
24682    text.char_indices()
24683        .rev()
24684        .chain([(0, '\0')])
24685        .filter_map(move |(index, codepoint)| {
24686            let prev_index = std::mem::replace(&mut prev_index, index);
24687            let prev_codepoint = prev_codepoint.replace(codepoint)?;
24688            if is_word_char(prev_codepoint) && is_word_char(codepoint) {
24689                None
24690            } else {
24691                let chunk = &text[prev_index..]; // go to end of string
24692                Some(chunk)
24693            }
24694        })
24695}
24696
24697pub trait RangeToAnchorExt: Sized {
24698    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
24699
24700    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
24701        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot());
24702        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
24703    }
24704}
24705
24706impl<T: ToOffset> RangeToAnchorExt for Range<T> {
24707    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
24708        let start_offset = self.start.to_offset(snapshot);
24709        let end_offset = self.end.to_offset(snapshot);
24710        if start_offset == end_offset {
24711            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
24712        } else {
24713            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
24714        }
24715    }
24716}
24717
24718pub trait RowExt {
24719    fn as_f64(&self) -> f64;
24720
24721    fn next_row(&self) -> Self;
24722
24723    fn previous_row(&self) -> Self;
24724
24725    fn minus(&self, other: Self) -> u32;
24726}
24727
24728impl RowExt for DisplayRow {
24729    fn as_f64(&self) -> f64 {
24730        self.0 as _
24731    }
24732
24733    fn next_row(&self) -> Self {
24734        Self(self.0 + 1)
24735    }
24736
24737    fn previous_row(&self) -> Self {
24738        Self(self.0.saturating_sub(1))
24739    }
24740
24741    fn minus(&self, other: Self) -> u32 {
24742        self.0 - other.0
24743    }
24744}
24745
24746impl RowExt for MultiBufferRow {
24747    fn as_f64(&self) -> f64 {
24748        self.0 as _
24749    }
24750
24751    fn next_row(&self) -> Self {
24752        Self(self.0 + 1)
24753    }
24754
24755    fn previous_row(&self) -> Self {
24756        Self(self.0.saturating_sub(1))
24757    }
24758
24759    fn minus(&self, other: Self) -> u32 {
24760        self.0 - other.0
24761    }
24762}
24763
24764trait RowRangeExt {
24765    type Row;
24766
24767    fn len(&self) -> usize;
24768
24769    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
24770}
24771
24772impl RowRangeExt for Range<MultiBufferRow> {
24773    type Row = MultiBufferRow;
24774
24775    fn len(&self) -> usize {
24776        (self.end.0 - self.start.0) as usize
24777    }
24778
24779    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
24780        (self.start.0..self.end.0).map(MultiBufferRow)
24781    }
24782}
24783
24784impl RowRangeExt for Range<DisplayRow> {
24785    type Row = DisplayRow;
24786
24787    fn len(&self) -> usize {
24788        (self.end.0 - self.start.0) as usize
24789    }
24790
24791    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
24792        (self.start.0..self.end.0).map(DisplayRow)
24793    }
24794}
24795
24796/// If select range has more than one line, we
24797/// just point the cursor to range.start.
24798fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
24799    if range.start.row == range.end.row {
24800        range
24801    } else {
24802        range.start..range.start
24803    }
24804}
24805pub struct KillRing(ClipboardItem);
24806impl Global for KillRing {}
24807
24808const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
24809
24810enum BreakpointPromptEditAction {
24811    Log,
24812    Condition,
24813    HitCondition,
24814}
24815
24816struct BreakpointPromptEditor {
24817    pub(crate) prompt: Entity<Editor>,
24818    editor: WeakEntity<Editor>,
24819    breakpoint_anchor: Anchor,
24820    breakpoint: Breakpoint,
24821    edit_action: BreakpointPromptEditAction,
24822    block_ids: HashSet<CustomBlockId>,
24823    editor_margins: Arc<Mutex<EditorMargins>>,
24824    _subscriptions: Vec<Subscription>,
24825}
24826
24827impl BreakpointPromptEditor {
24828    const MAX_LINES: u8 = 4;
24829
24830    fn new(
24831        editor: WeakEntity<Editor>,
24832        breakpoint_anchor: Anchor,
24833        breakpoint: Breakpoint,
24834        edit_action: BreakpointPromptEditAction,
24835        window: &mut Window,
24836        cx: &mut Context<Self>,
24837    ) -> Self {
24838        let base_text = match edit_action {
24839            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
24840            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
24841            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
24842        }
24843        .map(|msg| msg.to_string())
24844        .unwrap_or_default();
24845
24846        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
24847        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
24848
24849        let prompt = cx.new(|cx| {
24850            let mut prompt = Editor::new(
24851                EditorMode::AutoHeight {
24852                    min_lines: 1,
24853                    max_lines: Some(Self::MAX_LINES as usize),
24854                },
24855                buffer,
24856                None,
24857                window,
24858                cx,
24859            );
24860            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
24861            prompt.set_show_cursor_when_unfocused(false, cx);
24862            prompt.set_placeholder_text(
24863                match edit_action {
24864                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
24865                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
24866                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
24867                },
24868                window,
24869                cx,
24870            );
24871
24872            prompt
24873        });
24874
24875        Self {
24876            prompt,
24877            editor,
24878            breakpoint_anchor,
24879            breakpoint,
24880            edit_action,
24881            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
24882            block_ids: Default::default(),
24883            _subscriptions: vec![],
24884        }
24885    }
24886
24887    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
24888        self.block_ids.extend(block_ids)
24889    }
24890
24891    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
24892        if let Some(editor) = self.editor.upgrade() {
24893            let message = self
24894                .prompt
24895                .read(cx)
24896                .buffer
24897                .read(cx)
24898                .as_singleton()
24899                .expect("A multi buffer in breakpoint prompt isn't possible")
24900                .read(cx)
24901                .as_rope()
24902                .to_string();
24903
24904            editor.update(cx, |editor, cx| {
24905                editor.edit_breakpoint_at_anchor(
24906                    self.breakpoint_anchor,
24907                    self.breakpoint.clone(),
24908                    match self.edit_action {
24909                        BreakpointPromptEditAction::Log => {
24910                            BreakpointEditAction::EditLogMessage(message.into())
24911                        }
24912                        BreakpointPromptEditAction::Condition => {
24913                            BreakpointEditAction::EditCondition(message.into())
24914                        }
24915                        BreakpointPromptEditAction::HitCondition => {
24916                            BreakpointEditAction::EditHitCondition(message.into())
24917                        }
24918                    },
24919                    cx,
24920                );
24921
24922                editor.remove_blocks(self.block_ids.clone(), None, cx);
24923                cx.focus_self(window);
24924            });
24925        }
24926    }
24927
24928    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
24929        self.editor
24930            .update(cx, |editor, cx| {
24931                editor.remove_blocks(self.block_ids.clone(), None, cx);
24932                window.focus(&editor.focus_handle);
24933            })
24934            .log_err();
24935    }
24936
24937    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
24938        let settings = ThemeSettings::get_global(cx);
24939        let text_style = TextStyle {
24940            color: if self.prompt.read(cx).read_only(cx) {
24941                cx.theme().colors().text_disabled
24942            } else {
24943                cx.theme().colors().text
24944            },
24945            font_family: settings.buffer_font.family.clone(),
24946            font_fallbacks: settings.buffer_font.fallbacks.clone(),
24947            font_size: settings.buffer_font_size(cx).into(),
24948            font_weight: settings.buffer_font.weight,
24949            line_height: relative(settings.buffer_line_height.value()),
24950            ..Default::default()
24951        };
24952        EditorElement::new(
24953            &self.prompt,
24954            EditorStyle {
24955                background: cx.theme().colors().editor_background,
24956                local_player: cx.theme().players().local(),
24957                text: text_style,
24958                ..Default::default()
24959            },
24960        )
24961    }
24962}
24963
24964impl Render for BreakpointPromptEditor {
24965    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
24966        let editor_margins = *self.editor_margins.lock();
24967        let gutter_dimensions = editor_margins.gutter;
24968        h_flex()
24969            .key_context("Editor")
24970            .bg(cx.theme().colors().editor_background)
24971            .border_y_1()
24972            .border_color(cx.theme().status().info_border)
24973            .size_full()
24974            .py(window.line_height() / 2.5)
24975            .on_action(cx.listener(Self::confirm))
24976            .on_action(cx.listener(Self::cancel))
24977            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
24978            .child(div().flex_1().child(self.render_prompt_editor(cx)))
24979    }
24980}
24981
24982impl Focusable for BreakpointPromptEditor {
24983    fn focus_handle(&self, cx: &App) -> FocusHandle {
24984        self.prompt.focus_handle(cx)
24985    }
24986}
24987
24988fn all_edits_insertions_or_deletions(
24989    edits: &Vec<(Range<Anchor>, Arc<str>)>,
24990    snapshot: &MultiBufferSnapshot,
24991) -> bool {
24992    let mut all_insertions = true;
24993    let mut all_deletions = true;
24994
24995    for (range, new_text) in edits.iter() {
24996        let range_is_empty = range.to_offset(snapshot).is_empty();
24997        let text_is_empty = new_text.is_empty();
24998
24999        if range_is_empty != text_is_empty {
25000            if range_is_empty {
25001                all_deletions = false;
25002            } else {
25003                all_insertions = false;
25004            }
25005        } else {
25006            return false;
25007        }
25008
25009        if !all_insertions && !all_deletions {
25010            return false;
25011        }
25012    }
25013    all_insertions || all_deletions
25014}
25015
25016struct MissingEditPredictionKeybindingTooltip;
25017
25018impl Render for MissingEditPredictionKeybindingTooltip {
25019    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
25020        ui::tooltip_container(cx, |container, cx| {
25021            container
25022                .flex_shrink_0()
25023                .max_w_80()
25024                .min_h(rems_from_px(124.))
25025                .justify_between()
25026                .child(
25027                    v_flex()
25028                        .flex_1()
25029                        .text_ui_sm(cx)
25030                        .child(Label::new("Conflict with Accept Keybinding"))
25031                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
25032                )
25033                .child(
25034                    h_flex()
25035                        .pb_1()
25036                        .gap_1()
25037                        .items_end()
25038                        .w_full()
25039                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
25040                            window.dispatch_action(zed_actions::OpenKeymapFile.boxed_clone(), cx)
25041                        }))
25042                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
25043                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
25044                        })),
25045                )
25046        })
25047    }
25048}
25049
25050#[derive(Debug, Clone, Copy, PartialEq)]
25051pub struct LineHighlight {
25052    pub background: Background,
25053    pub border: Option<gpui::Hsla>,
25054    pub include_gutter: bool,
25055    pub type_id: Option<TypeId>,
25056}
25057
25058struct LineManipulationResult {
25059    pub new_text: String,
25060    pub line_count_before: usize,
25061    pub line_count_after: usize,
25062}
25063
25064fn render_diff_hunk_controls(
25065    row: u32,
25066    status: &DiffHunkStatus,
25067    hunk_range: Range<Anchor>,
25068    is_created_file: bool,
25069    line_height: Pixels,
25070    editor: &Entity<Editor>,
25071    _window: &mut Window,
25072    cx: &mut App,
25073) -> AnyElement {
25074    h_flex()
25075        .h(line_height)
25076        .mr_1()
25077        .gap_1()
25078        .px_0p5()
25079        .pb_1()
25080        .border_x_1()
25081        .border_b_1()
25082        .border_color(cx.theme().colors().border_variant)
25083        .rounded_b_lg()
25084        .bg(cx.theme().colors().editor_background)
25085        .gap_1()
25086        .block_mouse_except_scroll()
25087        .shadow_md()
25088        .child(if status.has_secondary_hunk() {
25089            Button::new(("stage", row as u64), "Stage")
25090                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
25091                .tooltip({
25092                    let focus_handle = editor.focus_handle(cx);
25093                    move |_window, cx| {
25094                        Tooltip::for_action_in(
25095                            "Stage Hunk",
25096                            &::git::ToggleStaged,
25097                            &focus_handle,
25098                            cx,
25099                        )
25100                    }
25101                })
25102                .on_click({
25103                    let editor = editor.clone();
25104                    move |_event, _window, cx| {
25105                        editor.update(cx, |editor, cx| {
25106                            editor.stage_or_unstage_diff_hunks(
25107                                true,
25108                                vec![hunk_range.start..hunk_range.start],
25109                                cx,
25110                            );
25111                        });
25112                    }
25113                })
25114        } else {
25115            Button::new(("unstage", row as u64), "Unstage")
25116                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
25117                .tooltip({
25118                    let focus_handle = editor.focus_handle(cx);
25119                    move |_window, cx| {
25120                        Tooltip::for_action_in(
25121                            "Unstage Hunk",
25122                            &::git::ToggleStaged,
25123                            &focus_handle,
25124                            cx,
25125                        )
25126                    }
25127                })
25128                .on_click({
25129                    let editor = editor.clone();
25130                    move |_event, _window, cx| {
25131                        editor.update(cx, |editor, cx| {
25132                            editor.stage_or_unstage_diff_hunks(
25133                                false,
25134                                vec![hunk_range.start..hunk_range.start],
25135                                cx,
25136                            );
25137                        });
25138                    }
25139                })
25140        })
25141        .child(
25142            Button::new(("restore", row as u64), "Restore")
25143                .tooltip({
25144                    let focus_handle = editor.focus_handle(cx);
25145                    move |_window, cx| {
25146                        Tooltip::for_action_in("Restore Hunk", &::git::Restore, &focus_handle, cx)
25147                    }
25148                })
25149                .on_click({
25150                    let editor = editor.clone();
25151                    move |_event, window, cx| {
25152                        editor.update(cx, |editor, cx| {
25153                            let snapshot = editor.snapshot(window, cx);
25154                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot());
25155                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
25156                        });
25157                    }
25158                })
25159                .disabled(is_created_file),
25160        )
25161        .when(
25162            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
25163            |el| {
25164                el.child(
25165                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
25166                        .shape(IconButtonShape::Square)
25167                        .icon_size(IconSize::Small)
25168                        // .disabled(!has_multiple_hunks)
25169                        .tooltip({
25170                            let focus_handle = editor.focus_handle(cx);
25171                            move |_window, cx| {
25172                                Tooltip::for_action_in("Next Hunk", &GoToHunk, &focus_handle, cx)
25173                            }
25174                        })
25175                        .on_click({
25176                            let editor = editor.clone();
25177                            move |_event, window, cx| {
25178                                editor.update(cx, |editor, cx| {
25179                                    let snapshot = editor.snapshot(window, cx);
25180                                    let position =
25181                                        hunk_range.end.to_point(&snapshot.buffer_snapshot());
25182                                    editor.go_to_hunk_before_or_after_position(
25183                                        &snapshot,
25184                                        position,
25185                                        Direction::Next,
25186                                        window,
25187                                        cx,
25188                                    );
25189                                    editor.expand_selected_diff_hunks(cx);
25190                                });
25191                            }
25192                        }),
25193                )
25194                .child(
25195                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
25196                        .shape(IconButtonShape::Square)
25197                        .icon_size(IconSize::Small)
25198                        // .disabled(!has_multiple_hunks)
25199                        .tooltip({
25200                            let focus_handle = editor.focus_handle(cx);
25201                            move |_window, cx| {
25202                                Tooltip::for_action_in(
25203                                    "Previous Hunk",
25204                                    &GoToPreviousHunk,
25205                                    &focus_handle,
25206                                    cx,
25207                                )
25208                            }
25209                        })
25210                        .on_click({
25211                            let editor = editor.clone();
25212                            move |_event, window, cx| {
25213                                editor.update(cx, |editor, cx| {
25214                                    let snapshot = editor.snapshot(window, cx);
25215                                    let point =
25216                                        hunk_range.start.to_point(&snapshot.buffer_snapshot());
25217                                    editor.go_to_hunk_before_or_after_position(
25218                                        &snapshot,
25219                                        point,
25220                                        Direction::Prev,
25221                                        window,
25222                                        cx,
25223                                    );
25224                                    editor.expand_selected_diff_hunks(cx);
25225                                });
25226                            }
25227                        }),
25228                )
25229            },
25230        )
25231        .into_any_element()
25232}
25233
25234pub fn multibuffer_context_lines(cx: &App) -> u32 {
25235    EditorSettings::try_get(cx)
25236        .map(|settings| settings.excerpt_context_lines)
25237        .unwrap_or(2)
25238        .min(32)
25239}