editor.rs

    1#![allow(rustdoc::private_intra_doc_links)]
    2//! This is the place where everything editor-related is stored (data-wise) and displayed (ui-wise).
    3//! The main point of interest in this crate is [`Editor`] type, which is used in every other Zed part as a user input element.
    4//! It comes in different flavors: single line, multiline and a fixed height one.
    5//!
    6//! Editor contains of multiple large submodules:
    7//! * [`element`] — the place where all rendering happens
    8//! * [`display_map`] - chunks up text in the editor into the logical blocks, establishes coordinates and mapping between each of them.
    9//!   Contains all metadata related to text transformations (folds, fake inlay text insertions, soft wraps, tab markup, etc.).
   10//!
   11//! All other submodules and structs are mostly concerned with holding editor data about the way it displays current buffer region(s).
   12//!
   13//! If you're looking to improve Vim mode, you should check out Vim crate that wraps Editor and overrides its behavior.
   14pub mod actions;
   15mod blink_manager;
   16mod clangd_ext;
   17pub mod code_context_menus;
   18pub mod display_map;
   19mod editor_settings;
   20mod element;
   21mod git;
   22mod highlight_matching_bracket;
   23mod hover_links;
   24pub mod hover_popover;
   25mod indent_guides;
   26mod inlays;
   27pub mod items;
   28mod jsx_tag_auto_close;
   29mod linked_editing_ranges;
   30mod lsp_colors;
   31mod lsp_ext;
   32mod mouse_context_menu;
   33pub mod movement;
   34mod persistence;
   35mod rust_analyzer_ext;
   36pub mod scroll;
   37mod selections_collection;
   38pub mod tasks;
   39
   40#[cfg(test)]
   41mod code_completion_tests;
   42#[cfg(test)]
   43mod edit_prediction_tests;
   44#[cfg(test)]
   45mod editor_tests;
   46mod signature_help;
   47#[cfg(any(test, feature = "test-support"))]
   48pub mod test;
   49
   50pub(crate) use actions::*;
   51pub use display_map::{ChunkRenderer, ChunkRendererContext, DisplayPoint, FoldPlaceholder};
   52pub use edit_prediction::Direction;
   53pub use editor_settings::{
   54    CurrentLineHighlight, DocumentColorsRenderMode, EditorSettings, HideMouseMode,
   55    ScrollBeyondLastLine, ScrollbarAxes, SearchSettings, ShowMinimap,
   56};
   57pub use element::{
   58    CursorLayout, EditorElement, HighlightedRange, HighlightedRangeLine, PointForPosition,
   59};
   60pub use git::blame::BlameRenderer;
   61pub use hover_popover::hover_markdown_style;
   62pub use inlays::Inlay;
   63pub use items::MAX_TAB_TITLE_LEN;
   64pub use lsp::CompletionContext;
   65pub use lsp_ext::lsp_tasks;
   66pub use multi_buffer::{
   67    Anchor, AnchorRangeExt, ExcerptId, ExcerptRange, MultiBuffer, MultiBufferSnapshot, PathKey,
   68    RowInfo, ToOffset, ToPoint,
   69};
   70pub use text::Bias;
   71
   72use ::git::{
   73    Restore,
   74    blame::{BlameEntry, ParsedCommitMessage},
   75    status::FileStatus,
   76};
   77use aho_corasick::AhoCorasick;
   78use anyhow::{Context as _, Result, anyhow};
   79use blink_manager::BlinkManager;
   80use buffer_diff::DiffHunkStatus;
   81use client::{Collaborator, ParticipantIndex, parse_zed_link};
   82use clock::ReplicaId;
   83use code_context_menus::{
   84    AvailableCodeAction, CodeActionContents, CodeActionsItem, CodeActionsMenu, CodeContextMenu,
   85    CompletionsMenu, ContextMenuOrigin,
   86};
   87use collections::{BTreeMap, HashMap, HashSet, VecDeque};
   88use convert_case::{Case, Casing};
   89use dap::TelemetrySpawnLocation;
   90use display_map::*;
   91use edit_prediction::{EditPredictionProvider, EditPredictionProviderHandle};
   92use editor_settings::{GoToDefinitionFallback, Minimap as MinimapSettings};
   93use element::{AcceptEditPredictionBinding, LineWithInvisibles, PositionMap, layout_line};
   94use futures::{
   95    FutureExt, StreamExt as _,
   96    future::{self, Shared, join},
   97    stream::FuturesUnordered,
   98};
   99use fuzzy::{StringMatch, StringMatchCandidate};
  100use git::blame::{GitBlame, GlobalBlameRenderer};
  101use gpui::{
  102    Action, Animation, AnimationExt, AnyElement, App, AppContext, AsyncWindowContext,
  103    AvailableSpace, Background, Bounds, ClickEvent, ClipboardEntry, ClipboardItem, Context,
  104    DispatchPhase, Edges, Entity, EntityInputHandler, EventEmitter, FocusHandle, FocusOutEvent,
  105    Focusable, FontId, FontWeight, Global, HighlightStyle, Hsla, KeyContext, Modifiers,
  106    MouseButton, MouseDownEvent, PaintQuad, ParentElement, Pixels, Render, ScrollHandle,
  107    SharedString, Size, Stateful, Styled, Subscription, Task, TextStyle, TextStyleRefinement,
  108    UTF16Selection, UnderlineStyle, UniformListScrollHandle, WeakEntity, WeakFocusHandle, Window,
  109    div, point, prelude::*, pulsating_between, px, relative, size,
  110};
  111use hover_links::{HoverLink, HoveredLinkState, find_file};
  112use hover_popover::{HoverState, hide_hover};
  113use indent_guides::ActiveIndentGuidesState;
  114use inlays::{InlaySplice, inlay_hints::InlayHintRefreshReason};
  115use itertools::{Either, Itertools};
  116use language::{
  117    AutoindentMode, BlockCommentConfig, BracketMatch, BracketPair, Buffer, BufferRow,
  118    BufferSnapshot, Capability, CharClassifier, CharKind, CharScopeContext, CodeLabel, CursorShape,
  119    DiagnosticEntryRef, DiffOptions, EditPredictionsMode, EditPreview, HighlightedText, IndentKind,
  120    IndentSize, Language, OffsetRangeExt, OutlineItem, Point, Runnable, RunnableRange, Selection,
  121    SelectionGoal, TextObject, TransactionId, TreeSitterOptions, WordsQuery,
  122    language_settings::{
  123        self, LspInsertMode, RewrapBehavior, WordsCompletionMode, all_language_settings,
  124        language_settings,
  125    },
  126    point_from_lsp, point_to_lsp, text_diff_with_options,
  127};
  128use linked_editing_ranges::refresh_linked_ranges;
  129use lsp::{
  130    CodeActionKind, CompletionItemKind, CompletionTriggerKind, InsertTextFormat, InsertTextMode,
  131    LanguageServerId,
  132};
  133use lsp_colors::LspColorData;
  134use markdown::Markdown;
  135use mouse_context_menu::MouseContextMenu;
  136use movement::TextLayoutDetails;
  137use multi_buffer::{
  138    ExcerptInfo, ExpandExcerptDirection, MultiBufferDiffHunk, MultiBufferPoint, MultiBufferRow,
  139};
  140use parking_lot::Mutex;
  141use persistence::DB;
  142use project::{
  143    BreakpointWithPosition, CodeAction, Completion, CompletionDisplayOptions, CompletionIntent,
  144    CompletionResponse, CompletionSource, DisableAiSettings, DocumentHighlight, InlayHint, InlayId,
  145    InvalidationStrategy, Location, LocationLink, PrepareRenameResponse, Project, ProjectItem,
  146    ProjectPath, ProjectTransaction, TaskSourceKind,
  147    debugger::{
  148        breakpoint_store::{
  149            Breakpoint, BreakpointEditAction, BreakpointSessionState, BreakpointState,
  150            BreakpointStore, BreakpointStoreEvent,
  151        },
  152        session::{Session, SessionEvent},
  153    },
  154    git_store::GitStoreEvent,
  155    lsp_store::{
  156        CacheInlayHints, CompletionDocumentation, FormatTrigger, LspFormatTarget,
  157        OpenLspBufferHandle,
  158    },
  159    project_settings::{DiagnosticSeverity, GoToDiagnosticSeverityFilter, ProjectSettings},
  160};
  161use rand::seq::SliceRandom;
  162use rpc::{ErrorCode, ErrorExt, proto::PeerId};
  163use scroll::{Autoscroll, OngoingScroll, ScrollAnchor, ScrollManager};
  164use selections_collection::{MutableSelectionsCollection, SelectionsCollection};
  165use serde::{Deserialize, Serialize};
  166use settings::{
  167    GitGutterSetting, RelativeLineNumbers, Settings, SettingsLocation, SettingsStore,
  168    update_settings_file,
  169};
  170use smallvec::{SmallVec, smallvec};
  171use snippet::Snippet;
  172use std::{
  173    any::{Any, TypeId},
  174    borrow::Cow,
  175    cell::{OnceCell, RefCell},
  176    cmp::{self, Ordering, Reverse},
  177    iter::{self, Peekable},
  178    mem,
  179    num::NonZeroU32,
  180    ops::{Deref, DerefMut, Not, Range, RangeInclusive},
  181    path::{Path, PathBuf},
  182    rc::Rc,
  183    sync::Arc,
  184    time::{Duration, Instant},
  185};
  186use task::{ResolvedTask, RunnableTag, TaskTemplate, TaskVariables};
  187use text::{BufferId, FromAnchor, OffsetUtf16, Rope, ToOffset as _};
  188use theme::{
  189    ActiveTheme, PlayerColor, StatusColors, SyntaxTheme, Theme, ThemeSettings,
  190    observe_buffer_font_size_adjustment,
  191};
  192use ui::{
  193    ButtonSize, ButtonStyle, ContextMenu, Disclosure, IconButton, IconButtonShape, IconName,
  194    IconSize, Indicator, Key, Tooltip, h_flex, prelude::*, scrollbars::ScrollbarAutoHide,
  195};
  196use util::{RangeExt, ResultExt, TryFutureExt, maybe, post_inc};
  197use workspace::{
  198    CollaboratorId, Item as WorkspaceItem, ItemId, ItemNavHistory, OpenInTerminal, OpenTerminal,
  199    RestoreOnStartupBehavior, SERIALIZATION_THROTTLE_TIME, SplitDirection, TabBarSettings, Toast,
  200    ViewId, Workspace, WorkspaceId, WorkspaceSettings,
  201    item::{ItemBufferKind, ItemHandle, PreviewTabsSettings, SaveOptions},
  202    notifications::{DetachAndPromptErr, NotificationId, NotifyTaskExt},
  203    searchable::SearchEvent,
  204};
  205
  206use crate::{
  207    code_context_menus::CompletionsMenuSource,
  208    editor_settings::MultiCursorModifier,
  209    hover_links::{find_url, find_url_from_range},
  210    inlays::{
  211        InlineValueCache,
  212        inlay_hints::{LspInlayHintData, inlay_hint_settings},
  213    },
  214    scroll::{ScrollOffset, ScrollPixelOffset},
  215    selections_collection::resolve_selections_wrapping_blocks,
  216    signature_help::{SignatureHelpHiddenBy, SignatureHelpState},
  217};
  218
  219pub const FILE_HEADER_HEIGHT: u32 = 2;
  220pub const MULTI_BUFFER_EXCERPT_HEADER_HEIGHT: u32 = 1;
  221const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500);
  222const MAX_LINE_LEN: usize = 1024;
  223const MIN_NAVIGATION_HISTORY_ROW_DELTA: i64 = 10;
  224const MAX_SELECTION_HISTORY_LEN: usize = 1024;
  225pub(crate) const CURSORS_VISIBLE_FOR: Duration = Duration::from_millis(2000);
  226#[doc(hidden)]
  227pub const CODE_ACTIONS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(250);
  228pub const SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(100);
  229
  230pub(crate) const CODE_ACTION_TIMEOUT: Duration = Duration::from_secs(5);
  231pub(crate) const FORMAT_TIMEOUT: Duration = Duration::from_secs(5);
  232pub(crate) const SCROLL_CENTER_TOP_BOTTOM_DEBOUNCE_TIMEOUT: Duration = Duration::from_secs(1);
  233pub const FETCH_COLORS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(150);
  234
  235pub(crate) const EDIT_PREDICTION_KEY_CONTEXT: &str = "edit_prediction";
  236pub(crate) const EDIT_PREDICTION_CONFLICT_KEY_CONTEXT: &str = "edit_prediction_conflict";
  237pub(crate) const MINIMAP_FONT_SIZE: AbsoluteLength = AbsoluteLength::Pixels(px(2.));
  238
  239pub type RenderDiffHunkControlsFn = Arc<
  240    dyn Fn(
  241        u32,
  242        &DiffHunkStatus,
  243        Range<Anchor>,
  244        bool,
  245        Pixels,
  246        &Entity<Editor>,
  247        &mut Window,
  248        &mut App,
  249    ) -> AnyElement,
  250>;
  251
  252enum ReportEditorEvent {
  253    Saved { auto_saved: bool },
  254    EditorOpened,
  255    Closed,
  256}
  257
  258impl ReportEditorEvent {
  259    pub fn event_type(&self) -> &'static str {
  260        match self {
  261            Self::Saved { .. } => "Editor Saved",
  262            Self::EditorOpened => "Editor Opened",
  263            Self::Closed => "Editor Closed",
  264        }
  265    }
  266}
  267
  268pub enum ActiveDebugLine {}
  269pub enum DebugStackFrameLine {}
  270enum DocumentHighlightRead {}
  271enum DocumentHighlightWrite {}
  272enum InputComposition {}
  273pub enum PendingInput {}
  274enum SelectedTextHighlight {}
  275
  276pub enum ConflictsOuter {}
  277pub enum ConflictsOurs {}
  278pub enum ConflictsTheirs {}
  279pub enum ConflictsOursMarker {}
  280pub enum ConflictsTheirsMarker {}
  281
  282#[derive(Debug, Copy, Clone, PartialEq, Eq)]
  283pub enum Navigated {
  284    Yes,
  285    No,
  286}
  287
  288impl Navigated {
  289    pub fn from_bool(yes: bool) -> Navigated {
  290        if yes { Navigated::Yes } else { Navigated::No }
  291    }
  292}
  293
  294#[derive(Debug, Clone, PartialEq, Eq)]
  295enum DisplayDiffHunk {
  296    Folded {
  297        display_row: DisplayRow,
  298    },
  299    Unfolded {
  300        is_created_file: bool,
  301        diff_base_byte_range: Range<usize>,
  302        display_row_range: Range<DisplayRow>,
  303        multi_buffer_range: Range<Anchor>,
  304        status: DiffHunkStatus,
  305    },
  306}
  307
  308pub enum HideMouseCursorOrigin {
  309    TypingAction,
  310    MovementAction,
  311}
  312
  313pub fn init(cx: &mut App) {
  314    cx.set_global(GlobalBlameRenderer(Arc::new(())));
  315
  316    workspace::register_project_item::<Editor>(cx);
  317    workspace::FollowableViewRegistry::register::<Editor>(cx);
  318    workspace::register_serializable_item::<Editor>(cx);
  319
  320    cx.observe_new(
  321        |workspace: &mut Workspace, _: Option<&mut Window>, _cx: &mut Context<Workspace>| {
  322            workspace.register_action(Editor::new_file);
  323            workspace.register_action(Editor::new_file_split);
  324            workspace.register_action(Editor::new_file_vertical);
  325            workspace.register_action(Editor::new_file_horizontal);
  326            workspace.register_action(Editor::cancel_language_server_work);
  327            workspace.register_action(Editor::toggle_focus);
  328        },
  329    )
  330    .detach();
  331
  332    cx.on_action(move |_: &workspace::NewFile, cx| {
  333        let app_state = workspace::AppState::global(cx);
  334        if let Some(app_state) = app_state.upgrade() {
  335            workspace::open_new(
  336                Default::default(),
  337                app_state,
  338                cx,
  339                |workspace, window, cx| {
  340                    Editor::new_file(workspace, &Default::default(), window, cx)
  341                },
  342            )
  343            .detach();
  344        }
  345    });
  346    cx.on_action(move |_: &workspace::NewWindow, cx| {
  347        let app_state = workspace::AppState::global(cx);
  348        if let Some(app_state) = app_state.upgrade() {
  349            workspace::open_new(
  350                Default::default(),
  351                app_state,
  352                cx,
  353                |workspace, window, cx| {
  354                    cx.activate(true);
  355                    Editor::new_file(workspace, &Default::default(), window, cx)
  356                },
  357            )
  358            .detach();
  359        }
  360    });
  361}
  362
  363pub fn set_blame_renderer(renderer: impl BlameRenderer + 'static, cx: &mut App) {
  364    cx.set_global(GlobalBlameRenderer(Arc::new(renderer)));
  365}
  366
  367pub trait DiagnosticRenderer {
  368    fn render_group(
  369        &self,
  370        diagnostic_group: Vec<DiagnosticEntryRef<'_, Point>>,
  371        buffer_id: BufferId,
  372        snapshot: EditorSnapshot,
  373        editor: WeakEntity<Editor>,
  374        cx: &mut App,
  375    ) -> Vec<BlockProperties<Anchor>>;
  376
  377    fn render_hover(
  378        &self,
  379        diagnostic_group: Vec<DiagnosticEntryRef<'_, Point>>,
  380        range: Range<Point>,
  381        buffer_id: BufferId,
  382        cx: &mut App,
  383    ) -> Option<Entity<markdown::Markdown>>;
  384
  385    fn open_link(
  386        &self,
  387        editor: &mut Editor,
  388        link: SharedString,
  389        window: &mut Window,
  390        cx: &mut Context<Editor>,
  391    );
  392}
  393
  394pub(crate) struct GlobalDiagnosticRenderer(pub Arc<dyn DiagnosticRenderer>);
  395
  396impl GlobalDiagnosticRenderer {
  397    fn global(cx: &App) -> Option<Arc<dyn DiagnosticRenderer>> {
  398        cx.try_global::<Self>().map(|g| g.0.clone())
  399    }
  400}
  401
  402impl gpui::Global for GlobalDiagnosticRenderer {}
  403pub fn set_diagnostic_renderer(renderer: impl DiagnosticRenderer + 'static, cx: &mut App) {
  404    cx.set_global(GlobalDiagnosticRenderer(Arc::new(renderer)));
  405}
  406
  407pub struct SearchWithinRange;
  408
  409trait InvalidationRegion {
  410    fn ranges(&self) -> &[Range<Anchor>];
  411}
  412
  413#[derive(Clone, Debug, PartialEq)]
  414pub enum SelectPhase {
  415    Begin {
  416        position: DisplayPoint,
  417        add: bool,
  418        click_count: usize,
  419    },
  420    BeginColumnar {
  421        position: DisplayPoint,
  422        reset: bool,
  423        mode: ColumnarMode,
  424        goal_column: u32,
  425    },
  426    Extend {
  427        position: DisplayPoint,
  428        click_count: usize,
  429    },
  430    Update {
  431        position: DisplayPoint,
  432        goal_column: u32,
  433        scroll_delta: gpui::Point<f32>,
  434    },
  435    End,
  436}
  437
  438#[derive(Clone, Debug, PartialEq)]
  439pub enum ColumnarMode {
  440    FromMouse,
  441    FromSelection,
  442}
  443
  444#[derive(Clone, Debug)]
  445pub enum SelectMode {
  446    Character,
  447    Word(Range<Anchor>),
  448    Line(Range<Anchor>),
  449    All,
  450}
  451
  452#[derive(Copy, Clone, Default, PartialEq, Eq, Debug)]
  453pub enum SizingBehavior {
  454    /// The editor will layout itself using `size_full` and will include the vertical
  455    /// scroll margin as requested by user settings.
  456    #[default]
  457    Default,
  458    /// The editor will layout itself using `size_full`, but will not have any
  459    /// vertical overscroll.
  460    ExcludeOverscrollMargin,
  461    /// The editor will request a vertical size according to its content and will be
  462    /// layouted without a vertical scroll margin.
  463    SizeByContent,
  464}
  465
  466#[derive(Clone, PartialEq, Eq, Debug)]
  467pub enum EditorMode {
  468    SingleLine,
  469    AutoHeight {
  470        min_lines: usize,
  471        max_lines: Option<usize>,
  472    },
  473    Full {
  474        /// When set to `true`, the editor will scale its UI elements with the buffer font size.
  475        scale_ui_elements_with_buffer_font_size: bool,
  476        /// When set to `true`, the editor will render a background for the active line.
  477        show_active_line_background: bool,
  478        /// Determines the sizing behavior for this editor
  479        sizing_behavior: SizingBehavior,
  480    },
  481    Minimap {
  482        parent: WeakEntity<Editor>,
  483    },
  484}
  485
  486impl EditorMode {
  487    pub fn full() -> Self {
  488        Self::Full {
  489            scale_ui_elements_with_buffer_font_size: true,
  490            show_active_line_background: true,
  491            sizing_behavior: SizingBehavior::Default,
  492        }
  493    }
  494
  495    #[inline]
  496    pub fn is_full(&self) -> bool {
  497        matches!(self, Self::Full { .. })
  498    }
  499
  500    #[inline]
  501    pub fn is_single_line(&self) -> bool {
  502        matches!(self, Self::SingleLine { .. })
  503    }
  504
  505    #[inline]
  506    fn is_minimap(&self) -> bool {
  507        matches!(self, Self::Minimap { .. })
  508    }
  509}
  510
  511#[derive(Copy, Clone, Debug)]
  512pub enum SoftWrap {
  513    /// Prefer not to wrap at all.
  514    ///
  515    /// Note: this is currently internal, as actually limited by [`crate::MAX_LINE_LEN`] until it wraps.
  516    /// The mode is used inside git diff hunks, where it's seems currently more useful to not wrap as much as possible.
  517    GitDiff,
  518    /// Prefer a single line generally, unless an overly long line is encountered.
  519    None,
  520    /// Soft wrap lines that exceed the editor width.
  521    EditorWidth,
  522    /// Soft wrap lines at the preferred line length.
  523    Column(u32),
  524    /// Soft wrap line at the preferred line length or the editor width (whichever is smaller).
  525    Bounded(u32),
  526}
  527
  528#[derive(Clone)]
  529pub struct EditorStyle {
  530    pub background: Hsla,
  531    pub border: Hsla,
  532    pub local_player: PlayerColor,
  533    pub text: TextStyle,
  534    pub scrollbar_width: Pixels,
  535    pub syntax: Arc<SyntaxTheme>,
  536    pub status: StatusColors,
  537    pub inlay_hints_style: HighlightStyle,
  538    pub edit_prediction_styles: EditPredictionStyles,
  539    pub unnecessary_code_fade: f32,
  540    pub show_underlines: bool,
  541}
  542
  543impl Default for EditorStyle {
  544    fn default() -> Self {
  545        Self {
  546            background: Hsla::default(),
  547            border: Hsla::default(),
  548            local_player: PlayerColor::default(),
  549            text: TextStyle::default(),
  550            scrollbar_width: Pixels::default(),
  551            syntax: Default::default(),
  552            // HACK: Status colors don't have a real default.
  553            // We should look into removing the status colors from the editor
  554            // style and retrieve them directly from the theme.
  555            status: StatusColors::dark(),
  556            inlay_hints_style: HighlightStyle::default(),
  557            edit_prediction_styles: EditPredictionStyles {
  558                insertion: HighlightStyle::default(),
  559                whitespace: HighlightStyle::default(),
  560            },
  561            unnecessary_code_fade: Default::default(),
  562            show_underlines: true,
  563        }
  564    }
  565}
  566
  567pub fn make_inlay_hints_style(cx: &mut App) -> HighlightStyle {
  568    let show_background = language_settings::language_settings(None, None, cx)
  569        .inlay_hints
  570        .show_background;
  571
  572    let mut style = cx.theme().syntax().get("hint");
  573
  574    if style.color.is_none() {
  575        style.color = Some(cx.theme().status().hint);
  576    }
  577
  578    if !show_background {
  579        style.background_color = None;
  580        return style;
  581    }
  582
  583    if style.background_color.is_none() {
  584        style.background_color = Some(cx.theme().status().hint_background);
  585    }
  586
  587    style
  588}
  589
  590pub fn make_suggestion_styles(cx: &mut App) -> EditPredictionStyles {
  591    EditPredictionStyles {
  592        insertion: HighlightStyle {
  593            color: Some(cx.theme().status().predictive),
  594            ..HighlightStyle::default()
  595        },
  596        whitespace: HighlightStyle {
  597            background_color: Some(cx.theme().status().created_background),
  598            ..HighlightStyle::default()
  599        },
  600    }
  601}
  602
  603type CompletionId = usize;
  604
  605pub(crate) enum EditDisplayMode {
  606    TabAccept,
  607    DiffPopover,
  608    Inline,
  609}
  610
  611enum EditPrediction {
  612    Edit {
  613        edits: Vec<(Range<Anchor>, Arc<str>)>,
  614        edit_preview: Option<EditPreview>,
  615        display_mode: EditDisplayMode,
  616        snapshot: BufferSnapshot,
  617    },
  618    /// Move to a specific location in the active editor
  619    MoveWithin {
  620        target: Anchor,
  621        snapshot: BufferSnapshot,
  622    },
  623    /// Move to a specific location in a different editor (not the active one)
  624    MoveOutside {
  625        target: language::Anchor,
  626        snapshot: BufferSnapshot,
  627    },
  628}
  629
  630struct EditPredictionState {
  631    inlay_ids: Vec<InlayId>,
  632    completion: EditPrediction,
  633    completion_id: Option<SharedString>,
  634    invalidation_range: Option<Range<Anchor>>,
  635}
  636
  637enum EditPredictionSettings {
  638    Disabled,
  639    Enabled {
  640        show_in_menu: bool,
  641        preview_requires_modifier: bool,
  642    },
  643}
  644
  645enum EditPredictionHighlight {}
  646
  647#[derive(Debug, Clone)]
  648struct InlineDiagnostic {
  649    message: SharedString,
  650    group_id: usize,
  651    is_primary: bool,
  652    start: Point,
  653    severity: lsp::DiagnosticSeverity,
  654}
  655
  656pub enum MenuEditPredictionsPolicy {
  657    Never,
  658    ByProvider,
  659}
  660
  661pub enum EditPredictionPreview {
  662    /// Modifier is not pressed
  663    Inactive { released_too_fast: bool },
  664    /// Modifier pressed
  665    Active {
  666        since: Instant,
  667        previous_scroll_position: Option<ScrollAnchor>,
  668    },
  669}
  670
  671impl EditPredictionPreview {
  672    pub fn released_too_fast(&self) -> bool {
  673        match self {
  674            EditPredictionPreview::Inactive { released_too_fast } => *released_too_fast,
  675            EditPredictionPreview::Active { .. } => false,
  676        }
  677    }
  678
  679    pub fn set_previous_scroll_position(&mut self, scroll_position: Option<ScrollAnchor>) {
  680        if let EditPredictionPreview::Active {
  681            previous_scroll_position,
  682            ..
  683        } = self
  684        {
  685            *previous_scroll_position = scroll_position;
  686        }
  687    }
  688}
  689
  690pub struct ContextMenuOptions {
  691    pub min_entries_visible: usize,
  692    pub max_entries_visible: usize,
  693    pub placement: Option<ContextMenuPlacement>,
  694}
  695
  696#[derive(Debug, Clone, PartialEq, Eq)]
  697pub enum ContextMenuPlacement {
  698    Above,
  699    Below,
  700}
  701
  702#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug, Default)]
  703struct EditorActionId(usize);
  704
  705impl EditorActionId {
  706    pub fn post_inc(&mut self) -> Self {
  707        let answer = self.0;
  708
  709        *self = Self(answer + 1);
  710
  711        Self(answer)
  712    }
  713}
  714
  715// type GetFieldEditorTheme = dyn Fn(&theme::Theme) -> theme::FieldEditor;
  716// type OverrideTextStyle = dyn Fn(&EditorStyle) -> Option<HighlightStyle>;
  717
  718type BackgroundHighlight = (fn(&Theme) -> Hsla, Arc<[Range<Anchor>]>);
  719type GutterHighlight = (fn(&App) -> Hsla, Vec<Range<Anchor>>);
  720
  721#[derive(Default)]
  722struct ScrollbarMarkerState {
  723    scrollbar_size: Size<Pixels>,
  724    dirty: bool,
  725    markers: Arc<[PaintQuad]>,
  726    pending_refresh: Option<Task<Result<()>>>,
  727}
  728
  729impl ScrollbarMarkerState {
  730    fn should_refresh(&self, scrollbar_size: Size<Pixels>) -> bool {
  731        self.pending_refresh.is_none() && (self.scrollbar_size != scrollbar_size || self.dirty)
  732    }
  733}
  734
  735#[derive(Clone, Copy, PartialEq, Eq)]
  736pub enum MinimapVisibility {
  737    Disabled,
  738    Enabled {
  739        /// The configuration currently present in the users settings.
  740        setting_configuration: bool,
  741        /// Whether to override the currently set visibility from the users setting.
  742        toggle_override: bool,
  743    },
  744}
  745
  746impl MinimapVisibility {
  747    fn for_mode(mode: &EditorMode, cx: &App) -> Self {
  748        if mode.is_full() {
  749            Self::Enabled {
  750                setting_configuration: EditorSettings::get_global(cx).minimap.minimap_enabled(),
  751                toggle_override: false,
  752            }
  753        } else {
  754            Self::Disabled
  755        }
  756    }
  757
  758    fn hidden(&self) -> Self {
  759        match *self {
  760            Self::Enabled {
  761                setting_configuration,
  762                ..
  763            } => Self::Enabled {
  764                setting_configuration,
  765                toggle_override: setting_configuration,
  766            },
  767            Self::Disabled => Self::Disabled,
  768        }
  769    }
  770
  771    fn disabled(&self) -> bool {
  772        matches!(*self, Self::Disabled)
  773    }
  774
  775    fn settings_visibility(&self) -> bool {
  776        match *self {
  777            Self::Enabled {
  778                setting_configuration,
  779                ..
  780            } => setting_configuration,
  781            _ => false,
  782        }
  783    }
  784
  785    fn visible(&self) -> bool {
  786        match *self {
  787            Self::Enabled {
  788                setting_configuration,
  789                toggle_override,
  790            } => setting_configuration ^ toggle_override,
  791            _ => false,
  792        }
  793    }
  794
  795    fn toggle_visibility(&self) -> Self {
  796        match *self {
  797            Self::Enabled {
  798                toggle_override,
  799                setting_configuration,
  800            } => Self::Enabled {
  801                setting_configuration,
  802                toggle_override: !toggle_override,
  803            },
  804            Self::Disabled => Self::Disabled,
  805        }
  806    }
  807}
  808
  809#[derive(Debug, Clone, Copy, PartialEq, Eq)]
  810pub enum BufferSerialization {
  811    All,
  812    NonDirtyBuffers,
  813}
  814
  815impl BufferSerialization {
  816    fn new(restore_unsaved_buffers: bool) -> Self {
  817        if restore_unsaved_buffers {
  818            Self::All
  819        } else {
  820            Self::NonDirtyBuffers
  821        }
  822    }
  823}
  824
  825#[derive(Clone, Debug)]
  826struct RunnableTasks {
  827    templates: Vec<(TaskSourceKind, TaskTemplate)>,
  828    offset: multi_buffer::Anchor,
  829    // We need the column at which the task context evaluation should take place (when we're spawning it via gutter).
  830    column: u32,
  831    // Values of all named captures, including those starting with '_'
  832    extra_variables: HashMap<String, String>,
  833    // Full range of the tagged region. We use it to determine which `extra_variables` to grab for context resolution in e.g. a modal.
  834    context_range: Range<BufferOffset>,
  835}
  836
  837impl RunnableTasks {
  838    fn resolve<'a>(
  839        &'a self,
  840        cx: &'a task::TaskContext,
  841    ) -> impl Iterator<Item = (TaskSourceKind, ResolvedTask)> + 'a {
  842        self.templates.iter().filter_map(|(kind, template)| {
  843            template
  844                .resolve_task(&kind.to_id_base(), cx)
  845                .map(|task| (kind.clone(), task))
  846        })
  847    }
  848}
  849
  850#[derive(Clone)]
  851pub struct ResolvedTasks {
  852    templates: SmallVec<[(TaskSourceKind, ResolvedTask); 1]>,
  853    position: Anchor,
  854}
  855
  856#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
  857struct BufferOffset(usize);
  858
  859/// Addons allow storing per-editor state in other crates (e.g. Vim)
  860pub trait Addon: 'static {
  861    fn extend_key_context(&self, _: &mut KeyContext, _: &App) {}
  862
  863    fn render_buffer_header_controls(
  864        &self,
  865        _: &ExcerptInfo,
  866        _: &Window,
  867        _: &App,
  868    ) -> Option<AnyElement> {
  869        None
  870    }
  871
  872    fn override_status_for_buffer_id(&self, _: BufferId, _: &App) -> Option<FileStatus> {
  873        None
  874    }
  875
  876    fn to_any(&self) -> &dyn std::any::Any;
  877
  878    fn to_any_mut(&mut self) -> Option<&mut dyn std::any::Any> {
  879        None
  880    }
  881}
  882
  883struct ChangeLocation {
  884    current: Option<Vec<Anchor>>,
  885    original: Vec<Anchor>,
  886}
  887impl ChangeLocation {
  888    fn locations(&self) -> &[Anchor] {
  889        self.current.as_ref().unwrap_or(&self.original)
  890    }
  891}
  892
  893/// A set of caret positions, registered when the editor was edited.
  894pub struct ChangeList {
  895    changes: Vec<ChangeLocation>,
  896    /// Currently "selected" change.
  897    position: Option<usize>,
  898}
  899
  900impl ChangeList {
  901    pub fn new() -> Self {
  902        Self {
  903            changes: Vec::new(),
  904            position: None,
  905        }
  906    }
  907
  908    /// Moves to the next change in the list (based on the direction given) and returns the caret positions for the next change.
  909    /// If reaches the end of the list in the direction, returns the corresponding change until called for a different direction.
  910    pub fn next_change(&mut self, count: usize, direction: Direction) -> Option<&[Anchor]> {
  911        if self.changes.is_empty() {
  912            return None;
  913        }
  914
  915        let prev = self.position.unwrap_or(self.changes.len());
  916        let next = if direction == Direction::Prev {
  917            prev.saturating_sub(count)
  918        } else {
  919            (prev + count).min(self.changes.len() - 1)
  920        };
  921        self.position = Some(next);
  922        self.changes.get(next).map(|change| change.locations())
  923    }
  924
  925    /// Adds a new change to the list, resetting the change list position.
  926    pub fn push_to_change_list(&mut self, group: bool, new_positions: Vec<Anchor>) {
  927        self.position.take();
  928        if let Some(last) = self.changes.last_mut()
  929            && group
  930        {
  931            last.current = Some(new_positions)
  932        } else {
  933            self.changes.push(ChangeLocation {
  934                original: new_positions,
  935                current: None,
  936            });
  937        }
  938    }
  939
  940    pub fn last(&self) -> Option<&[Anchor]> {
  941        self.changes.last().map(|change| change.locations())
  942    }
  943
  944    pub fn last_before_grouping(&self) -> Option<&[Anchor]> {
  945        self.changes.last().map(|change| change.original.as_slice())
  946    }
  947
  948    pub fn invert_last_group(&mut self) {
  949        if let Some(last) = self.changes.last_mut()
  950            && let Some(current) = last.current.as_mut()
  951        {
  952            mem::swap(&mut last.original, current);
  953        }
  954    }
  955}
  956
  957#[derive(Clone)]
  958struct InlineBlamePopoverState {
  959    scroll_handle: ScrollHandle,
  960    commit_message: Option<ParsedCommitMessage>,
  961    markdown: Entity<Markdown>,
  962}
  963
  964struct InlineBlamePopover {
  965    position: gpui::Point<Pixels>,
  966    hide_task: Option<Task<()>>,
  967    popover_bounds: Option<Bounds<Pixels>>,
  968    popover_state: InlineBlamePopoverState,
  969    keyboard_grace: bool,
  970}
  971
  972enum SelectionDragState {
  973    /// State when no drag related activity is detected.
  974    None,
  975    /// State when the mouse is down on a selection that is about to be dragged.
  976    ReadyToDrag {
  977        selection: Selection<Anchor>,
  978        click_position: gpui::Point<Pixels>,
  979        mouse_down_time: Instant,
  980    },
  981    /// State when the mouse is dragging the selection in the editor.
  982    Dragging {
  983        selection: Selection<Anchor>,
  984        drop_cursor: Selection<Anchor>,
  985        hide_drop_cursor: bool,
  986    },
  987}
  988
  989enum ColumnarSelectionState {
  990    FromMouse {
  991        selection_tail: Anchor,
  992        display_point: Option<DisplayPoint>,
  993    },
  994    FromSelection {
  995        selection_tail: Anchor,
  996    },
  997}
  998
  999/// Represents a breakpoint indicator that shows up when hovering over lines in the gutter that don't have
 1000/// a breakpoint on them.
 1001#[derive(Clone, Copy, Debug, PartialEq, Eq)]
 1002struct PhantomBreakpointIndicator {
 1003    display_row: DisplayRow,
 1004    /// There's a small debounce between hovering over the line and showing the indicator.
 1005    /// We don't want to show the indicator when moving the mouse from editor to e.g. project panel.
 1006    is_active: bool,
 1007    collides_with_existing_breakpoint: bool,
 1008}
 1009
 1010/// Zed's primary implementation of text input, allowing users to edit a [`MultiBuffer`].
 1011///
 1012/// See the [module level documentation](self) for more information.
 1013pub struct Editor {
 1014    focus_handle: FocusHandle,
 1015    last_focused_descendant: Option<WeakFocusHandle>,
 1016    /// The text buffer being edited
 1017    buffer: Entity<MultiBuffer>,
 1018    /// Map of how text in the buffer should be displayed.
 1019    /// Handles soft wraps, folds, fake inlay text insertions, etc.
 1020    pub display_map: Entity<DisplayMap>,
 1021    placeholder_display_map: Option<Entity<DisplayMap>>,
 1022    pub selections: SelectionsCollection,
 1023    pub scroll_manager: ScrollManager,
 1024    /// When inline assist editors are linked, they all render cursors because
 1025    /// typing enters text into each of them, even the ones that aren't focused.
 1026    pub(crate) show_cursor_when_unfocused: bool,
 1027    columnar_selection_state: Option<ColumnarSelectionState>,
 1028    add_selections_state: Option<AddSelectionsState>,
 1029    select_next_state: Option<SelectNextState>,
 1030    select_prev_state: Option<SelectNextState>,
 1031    selection_history: SelectionHistory,
 1032    defer_selection_effects: bool,
 1033    deferred_selection_effects_state: Option<DeferredSelectionEffectsState>,
 1034    autoclose_regions: Vec<AutocloseRegion>,
 1035    snippet_stack: InvalidationStack<SnippetState>,
 1036    select_syntax_node_history: SelectSyntaxNodeHistory,
 1037    ime_transaction: Option<TransactionId>,
 1038    pub diagnostics_max_severity: DiagnosticSeverity,
 1039    active_diagnostics: ActiveDiagnostic,
 1040    show_inline_diagnostics: bool,
 1041    inline_diagnostics_update: Task<()>,
 1042    inline_diagnostics_enabled: bool,
 1043    diagnostics_enabled: bool,
 1044    word_completions_enabled: bool,
 1045    inline_diagnostics: Vec<(Anchor, InlineDiagnostic)>,
 1046    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
 1047    hard_wrap: Option<usize>,
 1048    project: Option<Entity<Project>>,
 1049    semantics_provider: Option<Rc<dyn SemanticsProvider>>,
 1050    completion_provider: Option<Rc<dyn CompletionProvider>>,
 1051    collaboration_hub: Option<Box<dyn CollaborationHub>>,
 1052    blink_manager: Entity<BlinkManager>,
 1053    show_cursor_names: bool,
 1054    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
 1055    pub show_local_selections: bool,
 1056    mode: EditorMode,
 1057    show_breadcrumbs: bool,
 1058    show_gutter: bool,
 1059    show_scrollbars: ScrollbarAxes,
 1060    minimap_visibility: MinimapVisibility,
 1061    offset_content: bool,
 1062    disable_expand_excerpt_buttons: bool,
 1063    show_line_numbers: Option<bool>,
 1064    use_relative_line_numbers: Option<bool>,
 1065    show_git_diff_gutter: Option<bool>,
 1066    show_code_actions: Option<bool>,
 1067    show_runnables: Option<bool>,
 1068    show_breakpoints: Option<bool>,
 1069    show_wrap_guides: Option<bool>,
 1070    show_indent_guides: Option<bool>,
 1071    highlight_order: usize,
 1072    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
 1073    background_highlights: HashMap<HighlightKey, BackgroundHighlight>,
 1074    gutter_highlights: HashMap<TypeId, GutterHighlight>,
 1075    scrollbar_marker_state: ScrollbarMarkerState,
 1076    active_indent_guides_state: ActiveIndentGuidesState,
 1077    nav_history: Option<ItemNavHistory>,
 1078    context_menu: RefCell<Option<CodeContextMenu>>,
 1079    context_menu_options: Option<ContextMenuOptions>,
 1080    mouse_context_menu: Option<MouseContextMenu>,
 1081    completion_tasks: Vec<(CompletionId, Task<()>)>,
 1082    inline_blame_popover: Option<InlineBlamePopover>,
 1083    inline_blame_popover_show_task: Option<Task<()>>,
 1084    signature_help_state: SignatureHelpState,
 1085    auto_signature_help: Option<bool>,
 1086    find_all_references_task_sources: Vec<Anchor>,
 1087    next_completion_id: CompletionId,
 1088    available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
 1089    code_actions_task: Option<Task<Result<()>>>,
 1090    quick_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1091    debounced_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1092    document_highlights_task: Option<Task<()>>,
 1093    linked_editing_range_task: Option<Task<Option<()>>>,
 1094    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
 1095    pending_rename: Option<RenameState>,
 1096    searchable: bool,
 1097    cursor_shape: CursorShape,
 1098    current_line_highlight: Option<CurrentLineHighlight>,
 1099    autoindent_mode: Option<AutoindentMode>,
 1100    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
 1101    input_enabled: bool,
 1102    use_modal_editing: bool,
 1103    read_only: bool,
 1104    leader_id: Option<CollaboratorId>,
 1105    remote_id: Option<ViewId>,
 1106    pub hover_state: HoverState,
 1107    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
 1108    gutter_hovered: bool,
 1109    hovered_link_state: Option<HoveredLinkState>,
 1110    edit_prediction_provider: Option<RegisteredEditPredictionProvider>,
 1111    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
 1112    active_edit_prediction: Option<EditPredictionState>,
 1113    /// Used to prevent flickering as the user types while the menu is open
 1114    stale_edit_prediction_in_menu: Option<EditPredictionState>,
 1115    edit_prediction_settings: EditPredictionSettings,
 1116    edit_predictions_hidden_for_vim_mode: bool,
 1117    show_edit_predictions_override: Option<bool>,
 1118    menu_edit_predictions_policy: MenuEditPredictionsPolicy,
 1119    edit_prediction_preview: EditPredictionPreview,
 1120    edit_prediction_indent_conflict: bool,
 1121    edit_prediction_requires_modifier_in_indent_conflict: bool,
 1122    next_inlay_id: usize,
 1123    next_color_inlay_id: usize,
 1124    _subscriptions: Vec<Subscription>,
 1125    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
 1126    gutter_dimensions: GutterDimensions,
 1127    style: Option<EditorStyle>,
 1128    text_style_refinement: Option<TextStyleRefinement>,
 1129    next_editor_action_id: EditorActionId,
 1130    editor_actions: Rc<
 1131        RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&Editor, &mut Window, &mut Context<Self>)>>>,
 1132    >,
 1133    use_autoclose: bool,
 1134    use_auto_surround: bool,
 1135    auto_replace_emoji_shortcode: bool,
 1136    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1137    show_git_blame_gutter: bool,
 1138    show_git_blame_inline: bool,
 1139    show_git_blame_inline_delay_task: Option<Task<()>>,
 1140    git_blame_inline_enabled: bool,
 1141    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1142    buffer_serialization: Option<BufferSerialization>,
 1143    show_selection_menu: Option<bool>,
 1144    blame: Option<Entity<GitBlame>>,
 1145    blame_subscription: Option<Subscription>,
 1146    custom_context_menu: Option<
 1147        Box<
 1148            dyn 'static
 1149                + Fn(
 1150                    &mut Self,
 1151                    DisplayPoint,
 1152                    &mut Window,
 1153                    &mut Context<Self>,
 1154                ) -> Option<Entity<ui::ContextMenu>>,
 1155        >,
 1156    >,
 1157    last_bounds: Option<Bounds<Pixels>>,
 1158    last_position_map: Option<Rc<PositionMap>>,
 1159    expect_bounds_change: Option<Bounds<Pixels>>,
 1160    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
 1161    tasks_update_task: Option<Task<()>>,
 1162    breakpoint_store: Option<Entity<BreakpointStore>>,
 1163    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1164    hovered_diff_hunk_row: Option<DisplayRow>,
 1165    pull_diagnostics_task: Task<()>,
 1166    in_project_search: bool,
 1167    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1168    breadcrumb_header: Option<String>,
 1169    focused_block: Option<FocusedBlock>,
 1170    next_scroll_position: NextScrollCursorCenterTopBottom,
 1171    addons: HashMap<TypeId, Box<dyn Addon>>,
 1172    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1173    load_diff_task: Option<Shared<Task<()>>>,
 1174    /// Whether we are temporarily displaying a diff other than git's
 1175    temporary_diff_override: bool,
 1176    selection_mark_mode: bool,
 1177    toggle_fold_multiple_buffers: Task<()>,
 1178    _scroll_cursor_center_top_bottom_task: Task<()>,
 1179    serialize_selections: Task<()>,
 1180    serialize_folds: Task<()>,
 1181    mouse_cursor_hidden: bool,
 1182    minimap: Option<Entity<Self>>,
 1183    hide_mouse_mode: HideMouseMode,
 1184    pub change_list: ChangeList,
 1185    inline_value_cache: InlineValueCache,
 1186
 1187    selection_drag_state: SelectionDragState,
 1188    colors: Option<LspColorData>,
 1189    post_scroll_update: Task<()>,
 1190    refresh_colors_task: Task<()>,
 1191    inlay_hints: Option<LspInlayHintData>,
 1192    folding_newlines: Task<()>,
 1193    pub lookup_key: Option<Box<dyn Any + Send + Sync>>,
 1194}
 1195
 1196fn debounce_value(debounce_ms: u64) -> Option<Duration> {
 1197    if debounce_ms > 0 {
 1198        Some(Duration::from_millis(debounce_ms))
 1199    } else {
 1200        None
 1201    }
 1202}
 1203
 1204#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1205enum NextScrollCursorCenterTopBottom {
 1206    #[default]
 1207    Center,
 1208    Top,
 1209    Bottom,
 1210}
 1211
 1212impl NextScrollCursorCenterTopBottom {
 1213    fn next(&self) -> Self {
 1214        match self {
 1215            Self::Center => Self::Top,
 1216            Self::Top => Self::Bottom,
 1217            Self::Bottom => Self::Center,
 1218        }
 1219    }
 1220}
 1221
 1222#[derive(Clone)]
 1223pub struct EditorSnapshot {
 1224    pub mode: EditorMode,
 1225    show_gutter: bool,
 1226    show_line_numbers: Option<bool>,
 1227    show_git_diff_gutter: Option<bool>,
 1228    show_code_actions: Option<bool>,
 1229    show_runnables: Option<bool>,
 1230    show_breakpoints: Option<bool>,
 1231    git_blame_gutter_max_author_length: Option<usize>,
 1232    pub display_snapshot: DisplaySnapshot,
 1233    pub placeholder_display_snapshot: Option<DisplaySnapshot>,
 1234    is_focused: bool,
 1235    scroll_anchor: ScrollAnchor,
 1236    ongoing_scroll: OngoingScroll,
 1237    current_line_highlight: CurrentLineHighlight,
 1238    gutter_hovered: bool,
 1239}
 1240
 1241#[derive(Default, Debug, Clone, Copy)]
 1242pub struct GutterDimensions {
 1243    pub left_padding: Pixels,
 1244    pub right_padding: Pixels,
 1245    pub width: Pixels,
 1246    pub margin: Pixels,
 1247    pub git_blame_entries_width: Option<Pixels>,
 1248}
 1249
 1250impl GutterDimensions {
 1251    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1252        Self {
 1253            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1254            ..Default::default()
 1255        }
 1256    }
 1257
 1258    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1259        -cx.text_system().descent(font_id, font_size)
 1260    }
 1261    /// The full width of the space taken up by the gutter.
 1262    pub fn full_width(&self) -> Pixels {
 1263        self.margin + self.width
 1264    }
 1265
 1266    /// The width of the space reserved for the fold indicators,
 1267    /// use alongside 'justify_end' and `gutter_width` to
 1268    /// right align content with the line numbers
 1269    pub fn fold_area_width(&self) -> Pixels {
 1270        self.margin + self.right_padding
 1271    }
 1272}
 1273
 1274struct CharacterDimensions {
 1275    em_width: Pixels,
 1276    em_advance: Pixels,
 1277    line_height: Pixels,
 1278}
 1279
 1280#[derive(Debug)]
 1281pub struct RemoteSelection {
 1282    pub replica_id: ReplicaId,
 1283    pub selection: Selection<Anchor>,
 1284    pub cursor_shape: CursorShape,
 1285    pub collaborator_id: CollaboratorId,
 1286    pub line_mode: bool,
 1287    pub user_name: Option<SharedString>,
 1288    pub color: PlayerColor,
 1289}
 1290
 1291#[derive(Clone, Debug)]
 1292struct SelectionHistoryEntry {
 1293    selections: Arc<[Selection<Anchor>]>,
 1294    select_next_state: Option<SelectNextState>,
 1295    select_prev_state: Option<SelectNextState>,
 1296    add_selections_state: Option<AddSelectionsState>,
 1297}
 1298
 1299#[derive(Copy, Clone, Debug, PartialEq, Eq)]
 1300enum SelectionHistoryMode {
 1301    Normal,
 1302    Undoing,
 1303    Redoing,
 1304    Skipping,
 1305}
 1306
 1307#[derive(Clone, PartialEq, Eq, Hash)]
 1308struct HoveredCursor {
 1309    replica_id: ReplicaId,
 1310    selection_id: usize,
 1311}
 1312
 1313impl Default for SelectionHistoryMode {
 1314    fn default() -> Self {
 1315        Self::Normal
 1316    }
 1317}
 1318
 1319#[derive(Debug)]
 1320/// SelectionEffects controls the side-effects of updating the selection.
 1321///
 1322/// The default behaviour does "what you mostly want":
 1323/// - it pushes to the nav history if the cursor moved by >10 lines
 1324/// - it re-triggers completion requests
 1325/// - it scrolls to fit
 1326///
 1327/// You might want to modify these behaviours. For example when doing a "jump"
 1328/// like go to definition, we always want to add to nav history; but when scrolling
 1329/// in vim mode we never do.
 1330///
 1331/// Similarly, you might want to disable scrolling if you don't want the viewport to
 1332/// move.
 1333#[derive(Clone)]
 1334pub struct SelectionEffects {
 1335    nav_history: Option<bool>,
 1336    completions: bool,
 1337    scroll: Option<Autoscroll>,
 1338}
 1339
 1340impl Default for SelectionEffects {
 1341    fn default() -> Self {
 1342        Self {
 1343            nav_history: None,
 1344            completions: true,
 1345            scroll: Some(Autoscroll::fit()),
 1346        }
 1347    }
 1348}
 1349impl SelectionEffects {
 1350    pub fn scroll(scroll: Autoscroll) -> Self {
 1351        Self {
 1352            scroll: Some(scroll),
 1353            ..Default::default()
 1354        }
 1355    }
 1356
 1357    pub fn no_scroll() -> Self {
 1358        Self {
 1359            scroll: None,
 1360            ..Default::default()
 1361        }
 1362    }
 1363
 1364    pub fn completions(self, completions: bool) -> Self {
 1365        Self {
 1366            completions,
 1367            ..self
 1368        }
 1369    }
 1370
 1371    pub fn nav_history(self, nav_history: bool) -> Self {
 1372        Self {
 1373            nav_history: Some(nav_history),
 1374            ..self
 1375        }
 1376    }
 1377}
 1378
 1379struct DeferredSelectionEffectsState {
 1380    changed: bool,
 1381    effects: SelectionEffects,
 1382    old_cursor_position: Anchor,
 1383    history_entry: SelectionHistoryEntry,
 1384}
 1385
 1386#[derive(Default)]
 1387struct SelectionHistory {
 1388    #[allow(clippy::type_complexity)]
 1389    selections_by_transaction:
 1390        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1391    mode: SelectionHistoryMode,
 1392    undo_stack: VecDeque<SelectionHistoryEntry>,
 1393    redo_stack: VecDeque<SelectionHistoryEntry>,
 1394}
 1395
 1396impl SelectionHistory {
 1397    #[track_caller]
 1398    fn insert_transaction(
 1399        &mut self,
 1400        transaction_id: TransactionId,
 1401        selections: Arc<[Selection<Anchor>]>,
 1402    ) {
 1403        if selections.is_empty() {
 1404            log::error!(
 1405                "SelectionHistory::insert_transaction called with empty selections. Caller: {}",
 1406                std::panic::Location::caller()
 1407            );
 1408            return;
 1409        }
 1410        self.selections_by_transaction
 1411            .insert(transaction_id, (selections, None));
 1412    }
 1413
 1414    #[allow(clippy::type_complexity)]
 1415    fn transaction(
 1416        &self,
 1417        transaction_id: TransactionId,
 1418    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1419        self.selections_by_transaction.get(&transaction_id)
 1420    }
 1421
 1422    #[allow(clippy::type_complexity)]
 1423    fn transaction_mut(
 1424        &mut self,
 1425        transaction_id: TransactionId,
 1426    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1427        self.selections_by_transaction.get_mut(&transaction_id)
 1428    }
 1429
 1430    fn push(&mut self, entry: SelectionHistoryEntry) {
 1431        if !entry.selections.is_empty() {
 1432            match self.mode {
 1433                SelectionHistoryMode::Normal => {
 1434                    self.push_undo(entry);
 1435                    self.redo_stack.clear();
 1436                }
 1437                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1438                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1439                SelectionHistoryMode::Skipping => {}
 1440            }
 1441        }
 1442    }
 1443
 1444    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1445        if self
 1446            .undo_stack
 1447            .back()
 1448            .is_none_or(|e| e.selections != entry.selections)
 1449        {
 1450            self.undo_stack.push_back(entry);
 1451            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1452                self.undo_stack.pop_front();
 1453            }
 1454        }
 1455    }
 1456
 1457    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1458        if self
 1459            .redo_stack
 1460            .back()
 1461            .is_none_or(|e| e.selections != entry.selections)
 1462        {
 1463            self.redo_stack.push_back(entry);
 1464            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1465                self.redo_stack.pop_front();
 1466            }
 1467        }
 1468    }
 1469}
 1470
 1471#[derive(Clone, Copy)]
 1472pub struct RowHighlightOptions {
 1473    pub autoscroll: bool,
 1474    pub include_gutter: bool,
 1475}
 1476
 1477impl Default for RowHighlightOptions {
 1478    fn default() -> Self {
 1479        Self {
 1480            autoscroll: Default::default(),
 1481            include_gutter: true,
 1482        }
 1483    }
 1484}
 1485
 1486struct RowHighlight {
 1487    index: usize,
 1488    range: Range<Anchor>,
 1489    color: Hsla,
 1490    options: RowHighlightOptions,
 1491    type_id: TypeId,
 1492}
 1493
 1494#[derive(Clone, Debug)]
 1495struct AddSelectionsState {
 1496    groups: Vec<AddSelectionsGroup>,
 1497}
 1498
 1499#[derive(Clone, Debug)]
 1500struct AddSelectionsGroup {
 1501    above: bool,
 1502    stack: Vec<usize>,
 1503}
 1504
 1505#[derive(Clone)]
 1506struct SelectNextState {
 1507    query: AhoCorasick,
 1508    wordwise: bool,
 1509    done: bool,
 1510}
 1511
 1512impl std::fmt::Debug for SelectNextState {
 1513    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1514        f.debug_struct(std::any::type_name::<Self>())
 1515            .field("wordwise", &self.wordwise)
 1516            .field("done", &self.done)
 1517            .finish()
 1518    }
 1519}
 1520
 1521#[derive(Debug)]
 1522struct AutocloseRegion {
 1523    selection_id: usize,
 1524    range: Range<Anchor>,
 1525    pair: BracketPair,
 1526}
 1527
 1528#[derive(Debug)]
 1529struct SnippetState {
 1530    ranges: Vec<Vec<Range<Anchor>>>,
 1531    active_index: usize,
 1532    choices: Vec<Option<Vec<String>>>,
 1533}
 1534
 1535#[doc(hidden)]
 1536pub struct RenameState {
 1537    pub range: Range<Anchor>,
 1538    pub old_name: Arc<str>,
 1539    pub editor: Entity<Editor>,
 1540    block_id: CustomBlockId,
 1541}
 1542
 1543struct InvalidationStack<T>(Vec<T>);
 1544
 1545struct RegisteredEditPredictionProvider {
 1546    provider: Arc<dyn EditPredictionProviderHandle>,
 1547    _subscription: Subscription,
 1548}
 1549
 1550#[derive(Debug, PartialEq, Eq)]
 1551pub struct ActiveDiagnosticGroup {
 1552    pub active_range: Range<Anchor>,
 1553    pub active_message: String,
 1554    pub group_id: usize,
 1555    pub blocks: HashSet<CustomBlockId>,
 1556}
 1557
 1558#[derive(Debug, PartialEq, Eq)]
 1559
 1560pub(crate) enum ActiveDiagnostic {
 1561    None,
 1562    All,
 1563    Group(ActiveDiagnosticGroup),
 1564}
 1565
 1566#[derive(Serialize, Deserialize, Clone, Debug)]
 1567pub struct ClipboardSelection {
 1568    /// The number of bytes in this selection.
 1569    pub len: usize,
 1570    /// Whether this was a full-line selection.
 1571    pub is_entire_line: bool,
 1572    /// The indentation of the first line when this content was originally copied.
 1573    pub first_line_indent: u32,
 1574}
 1575
 1576// selections, scroll behavior, was newest selection reversed
 1577type SelectSyntaxNodeHistoryState = (
 1578    Box<[Selection<usize>]>,
 1579    SelectSyntaxNodeScrollBehavior,
 1580    bool,
 1581);
 1582
 1583#[derive(Default)]
 1584struct SelectSyntaxNodeHistory {
 1585    stack: Vec<SelectSyntaxNodeHistoryState>,
 1586    // disable temporarily to allow changing selections without losing the stack
 1587    pub disable_clearing: bool,
 1588}
 1589
 1590impl SelectSyntaxNodeHistory {
 1591    pub fn try_clear(&mut self) {
 1592        if !self.disable_clearing {
 1593            self.stack.clear();
 1594        }
 1595    }
 1596
 1597    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1598        self.stack.push(selection);
 1599    }
 1600
 1601    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1602        self.stack.pop()
 1603    }
 1604}
 1605
 1606enum SelectSyntaxNodeScrollBehavior {
 1607    CursorTop,
 1608    FitSelection,
 1609    CursorBottom,
 1610}
 1611
 1612#[derive(Debug)]
 1613pub(crate) struct NavigationData {
 1614    cursor_anchor: Anchor,
 1615    cursor_position: Point,
 1616    scroll_anchor: ScrollAnchor,
 1617    scroll_top_row: u32,
 1618}
 1619
 1620#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1621pub enum GotoDefinitionKind {
 1622    Symbol,
 1623    Declaration,
 1624    Type,
 1625    Implementation,
 1626}
 1627
 1628pub enum FormatTarget {
 1629    Buffers(HashSet<Entity<Buffer>>),
 1630    Ranges(Vec<Range<MultiBufferPoint>>),
 1631}
 1632
 1633pub(crate) struct FocusedBlock {
 1634    id: BlockId,
 1635    focus_handle: WeakFocusHandle,
 1636}
 1637
 1638#[derive(Clone)]
 1639enum JumpData {
 1640    MultiBufferRow {
 1641        row: MultiBufferRow,
 1642        line_offset_from_top: u32,
 1643    },
 1644    MultiBufferPoint {
 1645        excerpt_id: ExcerptId,
 1646        position: Point,
 1647        anchor: text::Anchor,
 1648        line_offset_from_top: u32,
 1649    },
 1650}
 1651
 1652pub enum MultibufferSelectionMode {
 1653    First,
 1654    All,
 1655}
 1656
 1657#[derive(Clone, Copy, Debug, Default)]
 1658pub struct RewrapOptions {
 1659    pub override_language_settings: bool,
 1660    pub preserve_existing_whitespace: bool,
 1661}
 1662
 1663impl Editor {
 1664    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1665        let buffer = cx.new(|cx| Buffer::local("", cx));
 1666        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1667        Self::new(EditorMode::SingleLine, buffer, None, window, cx)
 1668    }
 1669
 1670    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1671        let buffer = cx.new(|cx| Buffer::local("", cx));
 1672        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1673        Self::new(EditorMode::full(), buffer, None, window, cx)
 1674    }
 1675
 1676    pub fn auto_height(
 1677        min_lines: usize,
 1678        max_lines: usize,
 1679        window: &mut Window,
 1680        cx: &mut Context<Self>,
 1681    ) -> Self {
 1682        let buffer = cx.new(|cx| Buffer::local("", cx));
 1683        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1684        Self::new(
 1685            EditorMode::AutoHeight {
 1686                min_lines,
 1687                max_lines: Some(max_lines),
 1688            },
 1689            buffer,
 1690            None,
 1691            window,
 1692            cx,
 1693        )
 1694    }
 1695
 1696    /// Creates a new auto-height editor with a minimum number of lines but no maximum.
 1697    /// The editor grows as tall as needed to fit its content.
 1698    pub fn auto_height_unbounded(
 1699        min_lines: usize,
 1700        window: &mut Window,
 1701        cx: &mut Context<Self>,
 1702    ) -> Self {
 1703        let buffer = cx.new(|cx| Buffer::local("", cx));
 1704        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1705        Self::new(
 1706            EditorMode::AutoHeight {
 1707                min_lines,
 1708                max_lines: None,
 1709            },
 1710            buffer,
 1711            None,
 1712            window,
 1713            cx,
 1714        )
 1715    }
 1716
 1717    pub fn for_buffer(
 1718        buffer: Entity<Buffer>,
 1719        project: Option<Entity<Project>>,
 1720        window: &mut Window,
 1721        cx: &mut Context<Self>,
 1722    ) -> Self {
 1723        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1724        Self::new(EditorMode::full(), buffer, project, window, cx)
 1725    }
 1726
 1727    pub fn for_multibuffer(
 1728        buffer: Entity<MultiBuffer>,
 1729        project: Option<Entity<Project>>,
 1730        window: &mut Window,
 1731        cx: &mut Context<Self>,
 1732    ) -> Self {
 1733        Self::new(EditorMode::full(), buffer, project, window, cx)
 1734    }
 1735
 1736    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1737        let mut clone = Self::new(
 1738            self.mode.clone(),
 1739            self.buffer.clone(),
 1740            self.project.clone(),
 1741            window,
 1742            cx,
 1743        );
 1744        self.display_map.update(cx, |display_map, cx| {
 1745            let snapshot = display_map.snapshot(cx);
 1746            clone.display_map.update(cx, |display_map, cx| {
 1747                display_map.set_state(&snapshot, cx);
 1748            });
 1749        });
 1750        clone.folds_did_change(cx);
 1751        clone.selections.clone_state(&self.selections);
 1752        clone.scroll_manager.clone_state(&self.scroll_manager);
 1753        clone.searchable = self.searchable;
 1754        clone.read_only = self.read_only;
 1755        clone
 1756    }
 1757
 1758    pub fn new(
 1759        mode: EditorMode,
 1760        buffer: Entity<MultiBuffer>,
 1761        project: Option<Entity<Project>>,
 1762        window: &mut Window,
 1763        cx: &mut Context<Self>,
 1764    ) -> Self {
 1765        Editor::new_internal(mode, buffer, project, None, window, cx)
 1766    }
 1767
 1768    pub fn sticky_headers(&self, cx: &App) -> Option<Vec<OutlineItem<Anchor>>> {
 1769        let multi_buffer = self.buffer().read(cx);
 1770        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 1771        let multi_buffer_visible_start = self
 1772            .scroll_manager
 1773            .anchor()
 1774            .anchor
 1775            .to_point(&multi_buffer_snapshot);
 1776        let max_row = multi_buffer_snapshot.max_point().row;
 1777
 1778        let start_row = (multi_buffer_visible_start.row).min(max_row);
 1779        let end_row = (multi_buffer_visible_start.row + 10).min(max_row);
 1780
 1781        if let Some((excerpt_id, buffer_id, buffer)) = multi_buffer.read(cx).as_singleton() {
 1782            let outline_items = buffer
 1783                .outline_items_containing(
 1784                    Point::new(start_row, 0)..Point::new(end_row, 0),
 1785                    true,
 1786                    self.style().map(|style| style.syntax.as_ref()),
 1787                )
 1788                .into_iter()
 1789                .map(|outline_item| OutlineItem {
 1790                    depth: outline_item.depth,
 1791                    range: Anchor::range_in_buffer(*excerpt_id, buffer_id, outline_item.range),
 1792                    source_range_for_text: Anchor::range_in_buffer(
 1793                        *excerpt_id,
 1794                        buffer_id,
 1795                        outline_item.source_range_for_text,
 1796                    ),
 1797                    text: outline_item.text,
 1798                    highlight_ranges: outline_item.highlight_ranges,
 1799                    name_ranges: outline_item.name_ranges,
 1800                    body_range: outline_item
 1801                        .body_range
 1802                        .map(|range| Anchor::range_in_buffer(*excerpt_id, buffer_id, range)),
 1803                    annotation_range: outline_item
 1804                        .annotation_range
 1805                        .map(|range| Anchor::range_in_buffer(*excerpt_id, buffer_id, range)),
 1806                });
 1807            return Some(outline_items.collect());
 1808        }
 1809
 1810        None
 1811    }
 1812
 1813    fn new_internal(
 1814        mode: EditorMode,
 1815        multi_buffer: Entity<MultiBuffer>,
 1816        project: Option<Entity<Project>>,
 1817        display_map: Option<Entity<DisplayMap>>,
 1818        window: &mut Window,
 1819        cx: &mut Context<Self>,
 1820    ) -> Self {
 1821        debug_assert!(
 1822            display_map.is_none() || mode.is_minimap(),
 1823            "Providing a display map for a new editor is only intended for the minimap and might have unintended side effects otherwise!"
 1824        );
 1825
 1826        let full_mode = mode.is_full();
 1827        let is_minimap = mode.is_minimap();
 1828        let diagnostics_max_severity = if full_mode {
 1829            EditorSettings::get_global(cx)
 1830                .diagnostics_max_severity
 1831                .unwrap_or(DiagnosticSeverity::Hint)
 1832        } else {
 1833            DiagnosticSeverity::Off
 1834        };
 1835        let style = window.text_style();
 1836        let font_size = style.font_size.to_pixels(window.rem_size());
 1837        let editor = cx.entity().downgrade();
 1838        let fold_placeholder = FoldPlaceholder {
 1839            constrain_width: false,
 1840            render: Arc::new(move |fold_id, fold_range, cx| {
 1841                let editor = editor.clone();
 1842                div()
 1843                    .id(fold_id)
 1844                    .bg(cx.theme().colors().ghost_element_background)
 1845                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1846                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1847                    .rounded_xs()
 1848                    .size_full()
 1849                    .cursor_pointer()
 1850                    .child("")
 1851                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1852                    .on_click(move |_, _window, cx| {
 1853                        editor
 1854                            .update(cx, |editor, cx| {
 1855                                editor.unfold_ranges(
 1856                                    &[fold_range.start..fold_range.end],
 1857                                    true,
 1858                                    false,
 1859                                    cx,
 1860                                );
 1861                                cx.stop_propagation();
 1862                            })
 1863                            .ok();
 1864                    })
 1865                    .into_any()
 1866            }),
 1867            merge_adjacent: true,
 1868            ..FoldPlaceholder::default()
 1869        };
 1870        let display_map = display_map.unwrap_or_else(|| {
 1871            cx.new(|cx| {
 1872                DisplayMap::new(
 1873                    multi_buffer.clone(),
 1874                    style.font(),
 1875                    font_size,
 1876                    None,
 1877                    FILE_HEADER_HEIGHT,
 1878                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1879                    fold_placeholder,
 1880                    diagnostics_max_severity,
 1881                    cx,
 1882                )
 1883            })
 1884        });
 1885
 1886        let selections = SelectionsCollection::new();
 1887
 1888        let blink_manager = cx.new(|cx| {
 1889            let mut blink_manager = BlinkManager::new(CURSOR_BLINK_INTERVAL, cx);
 1890            if is_minimap {
 1891                blink_manager.disable(cx);
 1892            }
 1893            blink_manager
 1894        });
 1895
 1896        let soft_wrap_mode_override =
 1897            matches!(mode, EditorMode::SingleLine).then(|| language_settings::SoftWrap::None);
 1898
 1899        let mut project_subscriptions = Vec::new();
 1900        if full_mode && let Some(project) = project.as_ref() {
 1901            project_subscriptions.push(cx.subscribe_in(
 1902                project,
 1903                window,
 1904                |editor, _, event, window, cx| match event {
 1905                    project::Event::RefreshCodeLens => {
 1906                        // we always query lens with actions, without storing them, always refreshing them
 1907                    }
 1908                    project::Event::RefreshInlayHints {
 1909                        server_id,
 1910                        request_id,
 1911                    } => {
 1912                        editor.refresh_inlay_hints(
 1913                            InlayHintRefreshReason::RefreshRequested {
 1914                                server_id: *server_id,
 1915                                request_id: *request_id,
 1916                            },
 1917                            cx,
 1918                        );
 1919                    }
 1920                    project::Event::LanguageServerRemoved(..) => {
 1921                        if editor.tasks_update_task.is_none() {
 1922                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1923                        }
 1924                        editor.registered_buffers.clear();
 1925                        editor.register_visible_buffers(cx);
 1926                    }
 1927                    project::Event::LanguageServerAdded(..) => {
 1928                        if editor.tasks_update_task.is_none() {
 1929                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1930                        }
 1931                    }
 1932                    project::Event::SnippetEdit(id, snippet_edits) => {
 1933                        if let Some(buffer) = editor.buffer.read(cx).buffer(*id) {
 1934                            let focus_handle = editor.focus_handle(cx);
 1935                            if focus_handle.is_focused(window) {
 1936                                let snapshot = buffer.read(cx).snapshot();
 1937                                for (range, snippet) in snippet_edits {
 1938                                    let editor_range =
 1939                                        language::range_from_lsp(*range).to_offset(&snapshot);
 1940                                    editor
 1941                                        .insert_snippet(
 1942                                            &[editor_range],
 1943                                            snippet.clone(),
 1944                                            window,
 1945                                            cx,
 1946                                        )
 1947                                        .ok();
 1948                                }
 1949                            }
 1950                        }
 1951                    }
 1952                    project::Event::LanguageServerBufferRegistered { buffer_id, .. } => {
 1953                        let buffer_id = *buffer_id;
 1954                        if editor.buffer().read(cx).buffer(buffer_id).is_some() {
 1955                            editor.register_buffer(buffer_id, cx);
 1956                            editor.update_lsp_data(Some(buffer_id), window, cx);
 1957                            editor.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
 1958                            refresh_linked_ranges(editor, window, cx);
 1959                            editor.refresh_code_actions(window, cx);
 1960                            editor.refresh_document_highlights(cx);
 1961                        }
 1962                    }
 1963
 1964                    project::Event::EntryRenamed(transaction, project_path, abs_path) => {
 1965                        let Some(workspace) = editor.workspace() else {
 1966                            return;
 1967                        };
 1968                        let Some(active_editor) = workspace.read(cx).active_item_as::<Self>(cx)
 1969                        else {
 1970                            return;
 1971                        };
 1972
 1973                        if active_editor.entity_id() == cx.entity_id() {
 1974                            let entity_id = cx.entity_id();
 1975                            workspace.update(cx, |this, cx| {
 1976                                this.panes_mut()
 1977                                    .iter_mut()
 1978                                    .filter(|pane| pane.entity_id() != entity_id)
 1979                                    .for_each(|p| {
 1980                                        p.update(cx, |pane, _| {
 1981                                            pane.nav_history_mut().rename_item(
 1982                                                entity_id,
 1983                                                project_path.clone(),
 1984                                                abs_path.clone().into(),
 1985                                            );
 1986                                        })
 1987                                    });
 1988                            });
 1989                            let edited_buffers_already_open = {
 1990                                let other_editors: Vec<Entity<Editor>> = workspace
 1991                                    .read(cx)
 1992                                    .panes()
 1993                                    .iter()
 1994                                    .flat_map(|pane| pane.read(cx).items_of_type::<Editor>())
 1995                                    .filter(|editor| editor.entity_id() != cx.entity_id())
 1996                                    .collect();
 1997
 1998                                transaction.0.keys().all(|buffer| {
 1999                                    other_editors.iter().any(|editor| {
 2000                                        let multi_buffer = editor.read(cx).buffer();
 2001                                        multi_buffer.read(cx).is_singleton()
 2002                                            && multi_buffer.read(cx).as_singleton().map_or(
 2003                                                false,
 2004                                                |singleton| {
 2005                                                    singleton.entity_id() == buffer.entity_id()
 2006                                                },
 2007                                            )
 2008                                    })
 2009                                })
 2010                            };
 2011                            if !edited_buffers_already_open {
 2012                                let workspace = workspace.downgrade();
 2013                                let transaction = transaction.clone();
 2014                                cx.defer_in(window, move |_, window, cx| {
 2015                                    cx.spawn_in(window, async move |editor, cx| {
 2016                                        Self::open_project_transaction(
 2017                                            &editor,
 2018                                            workspace,
 2019                                            transaction,
 2020                                            "Rename".to_string(),
 2021                                            cx,
 2022                                        )
 2023                                        .await
 2024                                        .ok()
 2025                                    })
 2026                                    .detach();
 2027                                });
 2028                            }
 2029                        }
 2030                    }
 2031
 2032                    _ => {}
 2033                },
 2034            ));
 2035            if let Some(task_inventory) = project
 2036                .read(cx)
 2037                .task_store()
 2038                .read(cx)
 2039                .task_inventory()
 2040                .cloned()
 2041            {
 2042                project_subscriptions.push(cx.observe_in(
 2043                    &task_inventory,
 2044                    window,
 2045                    |editor, _, window, cx| {
 2046                        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2047                    },
 2048                ));
 2049            };
 2050
 2051            project_subscriptions.push(cx.subscribe_in(
 2052                &project.read(cx).breakpoint_store(),
 2053                window,
 2054                |editor, _, event, window, cx| match event {
 2055                    BreakpointStoreEvent::ClearDebugLines => {
 2056                        editor.clear_row_highlights::<ActiveDebugLine>();
 2057                        editor.refresh_inline_values(cx);
 2058                    }
 2059                    BreakpointStoreEvent::SetDebugLine => {
 2060                        if editor.go_to_active_debug_line(window, cx) {
 2061                            cx.stop_propagation();
 2062                        }
 2063
 2064                        editor.refresh_inline_values(cx);
 2065                    }
 2066                    _ => {}
 2067                },
 2068            ));
 2069            let git_store = project.read(cx).git_store().clone();
 2070            let project = project.clone();
 2071            project_subscriptions.push(cx.subscribe(&git_store, move |this, _, event, cx| {
 2072                if let GitStoreEvent::RepositoryAdded = event {
 2073                    this.load_diff_task = Some(
 2074                        update_uncommitted_diff_for_buffer(
 2075                            cx.entity(),
 2076                            &project,
 2077                            this.buffer.read(cx).all_buffers(),
 2078                            this.buffer.clone(),
 2079                            cx,
 2080                        )
 2081                        .shared(),
 2082                    );
 2083                }
 2084            }));
 2085        }
 2086
 2087        let buffer_snapshot = multi_buffer.read(cx).snapshot(cx);
 2088
 2089        let inlay_hint_settings =
 2090            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 2091        let focus_handle = cx.focus_handle();
 2092        if !is_minimap {
 2093            cx.on_focus(&focus_handle, window, Self::handle_focus)
 2094                .detach();
 2095            cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 2096                .detach();
 2097            cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 2098                .detach();
 2099            cx.on_blur(&focus_handle, window, Self::handle_blur)
 2100                .detach();
 2101            cx.observe_pending_input(window, Self::observe_pending_input)
 2102                .detach();
 2103        }
 2104
 2105        let show_indent_guides =
 2106            if matches!(mode, EditorMode::SingleLine | EditorMode::Minimap { .. }) {
 2107                Some(false)
 2108            } else {
 2109                None
 2110            };
 2111
 2112        let breakpoint_store = match (&mode, project.as_ref()) {
 2113            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 2114            _ => None,
 2115        };
 2116
 2117        let mut code_action_providers = Vec::new();
 2118        let mut load_uncommitted_diff = None;
 2119        if let Some(project) = project.clone() {
 2120            load_uncommitted_diff = Some(
 2121                update_uncommitted_diff_for_buffer(
 2122                    cx.entity(),
 2123                    &project,
 2124                    multi_buffer.read(cx).all_buffers(),
 2125                    multi_buffer.clone(),
 2126                    cx,
 2127                )
 2128                .shared(),
 2129            );
 2130            code_action_providers.push(Rc::new(project) as Rc<_>);
 2131        }
 2132
 2133        let mut editor = Self {
 2134            focus_handle,
 2135            show_cursor_when_unfocused: false,
 2136            last_focused_descendant: None,
 2137            buffer: multi_buffer.clone(),
 2138            display_map: display_map.clone(),
 2139            placeholder_display_map: None,
 2140            selections,
 2141            scroll_manager: ScrollManager::new(cx),
 2142            columnar_selection_state: None,
 2143            add_selections_state: None,
 2144            select_next_state: None,
 2145            select_prev_state: None,
 2146            selection_history: SelectionHistory::default(),
 2147            defer_selection_effects: false,
 2148            deferred_selection_effects_state: None,
 2149            autoclose_regions: Vec::new(),
 2150            snippet_stack: InvalidationStack::default(),
 2151            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 2152            ime_transaction: None,
 2153            active_diagnostics: ActiveDiagnostic::None,
 2154            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 2155            inline_diagnostics_update: Task::ready(()),
 2156            inline_diagnostics: Vec::new(),
 2157            soft_wrap_mode_override,
 2158            diagnostics_max_severity,
 2159            hard_wrap: None,
 2160            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 2161            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 2162            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 2163            project,
 2164            blink_manager: blink_manager.clone(),
 2165            show_local_selections: true,
 2166            show_scrollbars: ScrollbarAxes {
 2167                horizontal: full_mode,
 2168                vertical: full_mode,
 2169            },
 2170            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 2171            offset_content: !matches!(mode, EditorMode::SingleLine),
 2172            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 2173            show_gutter: full_mode,
 2174            show_line_numbers: (!full_mode).then_some(false),
 2175            use_relative_line_numbers: None,
 2176            disable_expand_excerpt_buttons: !full_mode,
 2177            show_git_diff_gutter: None,
 2178            show_code_actions: None,
 2179            show_runnables: None,
 2180            show_breakpoints: None,
 2181            show_wrap_guides: None,
 2182            show_indent_guides,
 2183            highlight_order: 0,
 2184            highlighted_rows: HashMap::default(),
 2185            background_highlights: HashMap::default(),
 2186            gutter_highlights: HashMap::default(),
 2187            scrollbar_marker_state: ScrollbarMarkerState::default(),
 2188            active_indent_guides_state: ActiveIndentGuidesState::default(),
 2189            nav_history: None,
 2190            context_menu: RefCell::new(None),
 2191            context_menu_options: None,
 2192            mouse_context_menu: None,
 2193            completion_tasks: Vec::new(),
 2194            inline_blame_popover: None,
 2195            inline_blame_popover_show_task: None,
 2196            signature_help_state: SignatureHelpState::default(),
 2197            auto_signature_help: None,
 2198            find_all_references_task_sources: Vec::new(),
 2199            next_completion_id: 0,
 2200            next_inlay_id: 0,
 2201            code_action_providers,
 2202            available_code_actions: None,
 2203            code_actions_task: None,
 2204            quick_selection_highlight_task: None,
 2205            debounced_selection_highlight_task: None,
 2206            document_highlights_task: None,
 2207            linked_editing_range_task: None,
 2208            pending_rename: None,
 2209            searchable: !is_minimap,
 2210            cursor_shape: EditorSettings::get_global(cx)
 2211                .cursor_shape
 2212                .unwrap_or_default(),
 2213            current_line_highlight: None,
 2214            autoindent_mode: Some(AutoindentMode::EachLine),
 2215
 2216            workspace: None,
 2217            input_enabled: !is_minimap,
 2218            use_modal_editing: full_mode,
 2219            read_only: is_minimap,
 2220            use_autoclose: true,
 2221            use_auto_surround: true,
 2222            auto_replace_emoji_shortcode: false,
 2223            jsx_tag_auto_close_enabled_in_any_buffer: false,
 2224            leader_id: None,
 2225            remote_id: None,
 2226            hover_state: HoverState::default(),
 2227            pending_mouse_down: None,
 2228            hovered_link_state: None,
 2229            edit_prediction_provider: None,
 2230            active_edit_prediction: None,
 2231            stale_edit_prediction_in_menu: None,
 2232            edit_prediction_preview: EditPredictionPreview::Inactive {
 2233                released_too_fast: false,
 2234            },
 2235            inline_diagnostics_enabled: full_mode,
 2236            diagnostics_enabled: full_mode,
 2237            word_completions_enabled: full_mode,
 2238            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 2239            gutter_hovered: false,
 2240            pixel_position_of_newest_cursor: None,
 2241            last_bounds: None,
 2242            last_position_map: None,
 2243            expect_bounds_change: None,
 2244            gutter_dimensions: GutterDimensions::default(),
 2245            style: None,
 2246            show_cursor_names: false,
 2247            hovered_cursors: HashMap::default(),
 2248            next_editor_action_id: EditorActionId::default(),
 2249            editor_actions: Rc::default(),
 2250            edit_predictions_hidden_for_vim_mode: false,
 2251            show_edit_predictions_override: None,
 2252            menu_edit_predictions_policy: MenuEditPredictionsPolicy::ByProvider,
 2253            edit_prediction_settings: EditPredictionSettings::Disabled,
 2254            edit_prediction_indent_conflict: false,
 2255            edit_prediction_requires_modifier_in_indent_conflict: true,
 2256            custom_context_menu: None,
 2257            show_git_blame_gutter: false,
 2258            show_git_blame_inline: false,
 2259            show_selection_menu: None,
 2260            show_git_blame_inline_delay_task: None,
 2261            git_blame_inline_enabled: full_mode
 2262                && ProjectSettings::get_global(cx).git.inline_blame.enabled,
 2263            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 2264            buffer_serialization: is_minimap.not().then(|| {
 2265                BufferSerialization::new(
 2266                    ProjectSettings::get_global(cx)
 2267                        .session
 2268                        .restore_unsaved_buffers,
 2269                )
 2270            }),
 2271            blame: None,
 2272            blame_subscription: None,
 2273            tasks: BTreeMap::default(),
 2274
 2275            breakpoint_store,
 2276            gutter_breakpoint_indicator: (None, None),
 2277            hovered_diff_hunk_row: None,
 2278            _subscriptions: (!is_minimap)
 2279                .then(|| {
 2280                    vec![
 2281                        cx.observe(&multi_buffer, Self::on_buffer_changed),
 2282                        cx.subscribe_in(&multi_buffer, window, Self::on_buffer_event),
 2283                        cx.observe_in(&display_map, window, Self::on_display_map_changed),
 2284                        cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 2285                        cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 2286                        observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 2287                        cx.observe_window_activation(window, |editor, window, cx| {
 2288                            let active = window.is_window_active();
 2289                            editor.blink_manager.update(cx, |blink_manager, cx| {
 2290                                if active {
 2291                                    blink_manager.enable(cx);
 2292                                } else {
 2293                                    blink_manager.disable(cx);
 2294                                }
 2295                            });
 2296                            if active {
 2297                                editor.show_mouse_cursor(cx);
 2298                            }
 2299                        }),
 2300                    ]
 2301                })
 2302                .unwrap_or_default(),
 2303            tasks_update_task: None,
 2304            pull_diagnostics_task: Task::ready(()),
 2305            colors: None,
 2306            refresh_colors_task: Task::ready(()),
 2307            inlay_hints: None,
 2308            next_color_inlay_id: 0,
 2309            post_scroll_update: Task::ready(()),
 2310            linked_edit_ranges: Default::default(),
 2311            in_project_search: false,
 2312            previous_search_ranges: None,
 2313            breadcrumb_header: None,
 2314            focused_block: None,
 2315            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 2316            addons: HashMap::default(),
 2317            registered_buffers: HashMap::default(),
 2318            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 2319            selection_mark_mode: false,
 2320            toggle_fold_multiple_buffers: Task::ready(()),
 2321            serialize_selections: Task::ready(()),
 2322            serialize_folds: Task::ready(()),
 2323            text_style_refinement: None,
 2324            load_diff_task: load_uncommitted_diff,
 2325            temporary_diff_override: false,
 2326            mouse_cursor_hidden: false,
 2327            minimap: None,
 2328            hide_mouse_mode: EditorSettings::get_global(cx)
 2329                .hide_mouse
 2330                .unwrap_or_default(),
 2331            change_list: ChangeList::new(),
 2332            mode,
 2333            selection_drag_state: SelectionDragState::None,
 2334            folding_newlines: Task::ready(()),
 2335            lookup_key: None,
 2336        };
 2337
 2338        if is_minimap {
 2339            return editor;
 2340        }
 2341
 2342        if let Some(breakpoints) = editor.breakpoint_store.as_ref() {
 2343            editor
 2344                ._subscriptions
 2345                .push(cx.observe(breakpoints, |_, _, cx| {
 2346                    cx.notify();
 2347                }));
 2348        }
 2349        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2350        editor._subscriptions.extend(project_subscriptions);
 2351
 2352        editor._subscriptions.push(cx.subscribe_in(
 2353            &cx.entity(),
 2354            window,
 2355            |editor, _, e: &EditorEvent, window, cx| match e {
 2356                EditorEvent::ScrollPositionChanged { local, .. } => {
 2357                    if *local {
 2358                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 2359                        editor.inline_blame_popover.take();
 2360                        let new_anchor = editor.scroll_manager.anchor();
 2361                        let snapshot = editor.snapshot(window, cx);
 2362                        editor.update_restoration_data(cx, move |data| {
 2363                            data.scroll_position = (
 2364                                new_anchor.top_row(snapshot.buffer_snapshot()),
 2365                                new_anchor.offset,
 2366                            );
 2367                        });
 2368
 2369                        editor.post_scroll_update = cx.spawn_in(window, async move |editor, cx| {
 2370                            cx.background_executor()
 2371                                .timer(Duration::from_millis(50))
 2372                                .await;
 2373                            editor
 2374                                .update_in(cx, |editor, window, cx| {
 2375                                    editor.register_visible_buffers(cx);
 2376                                    editor.refresh_colors_for_visible_range(None, window, cx);
 2377                                    editor.refresh_inlay_hints(
 2378                                        InlayHintRefreshReason::NewLinesShown,
 2379                                        cx,
 2380                                    );
 2381                                })
 2382                                .ok();
 2383                        });
 2384                    }
 2385                }
 2386                EditorEvent::Edited { .. } => {
 2387                    if vim_flavor(cx).is_none() {
 2388                        let display_map = editor.display_snapshot(cx);
 2389                        let selections = editor.selections.all_adjusted_display(&display_map);
 2390                        let pop_state = editor
 2391                            .change_list
 2392                            .last()
 2393                            .map(|previous| {
 2394                                previous.len() == selections.len()
 2395                                    && previous.iter().enumerate().all(|(ix, p)| {
 2396                                        p.to_display_point(&display_map).row()
 2397                                            == selections[ix].head().row()
 2398                                    })
 2399                            })
 2400                            .unwrap_or(false);
 2401                        let new_positions = selections
 2402                            .into_iter()
 2403                            .map(|s| display_map.display_point_to_anchor(s.head(), Bias::Left))
 2404                            .collect();
 2405                        editor
 2406                            .change_list
 2407                            .push_to_change_list(pop_state, new_positions);
 2408                    }
 2409                }
 2410                _ => (),
 2411            },
 2412        ));
 2413
 2414        if let Some(dap_store) = editor
 2415            .project
 2416            .as_ref()
 2417            .map(|project| project.read(cx).dap_store())
 2418        {
 2419            let weak_editor = cx.weak_entity();
 2420
 2421            editor
 2422                ._subscriptions
 2423                .push(
 2424                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2425                        let session_entity = cx.entity();
 2426                        weak_editor
 2427                            .update(cx, |editor, cx| {
 2428                                editor._subscriptions.push(
 2429                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2430                                );
 2431                            })
 2432                            .ok();
 2433                    }),
 2434                );
 2435
 2436            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2437                editor
 2438                    ._subscriptions
 2439                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2440            }
 2441        }
 2442
 2443        // skip adding the initial selection to selection history
 2444        editor.selection_history.mode = SelectionHistoryMode::Skipping;
 2445        editor.end_selection(window, cx);
 2446        editor.selection_history.mode = SelectionHistoryMode::Normal;
 2447
 2448        editor.scroll_manager.show_scrollbars(window, cx);
 2449        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut editor, &multi_buffer, cx);
 2450
 2451        if full_mode {
 2452            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2453            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2454
 2455            if editor.git_blame_inline_enabled {
 2456                editor.start_git_blame_inline(false, window, cx);
 2457            }
 2458
 2459            editor.go_to_active_debug_line(window, cx);
 2460
 2461            editor.minimap =
 2462                editor.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2463            editor.colors = Some(LspColorData::new(cx));
 2464            editor.inlay_hints = Some(LspInlayHintData::new(inlay_hint_settings));
 2465
 2466            if let Some(buffer) = multi_buffer.read(cx).as_singleton() {
 2467                editor.register_buffer(buffer.read(cx).remote_id(), cx);
 2468            }
 2469            editor.update_lsp_data(None, window, cx);
 2470            editor.report_editor_event(ReportEditorEvent::EditorOpened, None, cx);
 2471        }
 2472
 2473        editor
 2474    }
 2475
 2476    pub fn display_snapshot(&self, cx: &mut App) -> DisplaySnapshot {
 2477        self.display_map.update(cx, |map, cx| map.snapshot(cx))
 2478    }
 2479
 2480    pub fn deploy_mouse_context_menu(
 2481        &mut self,
 2482        position: gpui::Point<Pixels>,
 2483        context_menu: Entity<ContextMenu>,
 2484        window: &mut Window,
 2485        cx: &mut Context<Self>,
 2486    ) {
 2487        self.mouse_context_menu = Some(MouseContextMenu::new(
 2488            self,
 2489            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2490            context_menu,
 2491            window,
 2492            cx,
 2493        ));
 2494    }
 2495
 2496    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2497        self.mouse_context_menu
 2498            .as_ref()
 2499            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2500    }
 2501
 2502    pub fn is_range_selected(&mut self, range: &Range<Anchor>, cx: &mut Context<Self>) -> bool {
 2503        if self
 2504            .selections
 2505            .pending_anchor()
 2506            .is_some_and(|pending_selection| {
 2507                let snapshot = self.buffer().read(cx).snapshot(cx);
 2508                pending_selection.range().includes(range, &snapshot)
 2509            })
 2510        {
 2511            return true;
 2512        }
 2513
 2514        self.selections
 2515            .disjoint_in_range::<usize>(range.clone(), &self.display_snapshot(cx))
 2516            .into_iter()
 2517            .any(|selection| {
 2518                // This is needed to cover a corner case, if we just check for an existing
 2519                // selection in the fold range, having a cursor at the start of the fold
 2520                // marks it as selected. Non-empty selections don't cause this.
 2521                let length = selection.end - selection.start;
 2522                length > 0
 2523            })
 2524    }
 2525
 2526    pub fn key_context(&self, window: &mut Window, cx: &mut App) -> KeyContext {
 2527        self.key_context_internal(self.has_active_edit_prediction(), window, cx)
 2528    }
 2529
 2530    fn key_context_internal(
 2531        &self,
 2532        has_active_edit_prediction: bool,
 2533        window: &mut Window,
 2534        cx: &mut App,
 2535    ) -> KeyContext {
 2536        let mut key_context = KeyContext::new_with_defaults();
 2537        key_context.add("Editor");
 2538        let mode = match self.mode {
 2539            EditorMode::SingleLine => "single_line",
 2540            EditorMode::AutoHeight { .. } => "auto_height",
 2541            EditorMode::Minimap { .. } => "minimap",
 2542            EditorMode::Full { .. } => "full",
 2543        };
 2544
 2545        if EditorSettings::jupyter_enabled(cx) {
 2546            key_context.add("jupyter");
 2547        }
 2548
 2549        key_context.set("mode", mode);
 2550        if self.pending_rename.is_some() {
 2551            key_context.add("renaming");
 2552        }
 2553
 2554        if let Some(snippet_stack) = self.snippet_stack.last() {
 2555            key_context.add("in_snippet");
 2556
 2557            if snippet_stack.active_index > 0 {
 2558                key_context.add("has_previous_tabstop");
 2559            }
 2560
 2561            if snippet_stack.active_index < snippet_stack.ranges.len().saturating_sub(1) {
 2562                key_context.add("has_next_tabstop");
 2563            }
 2564        }
 2565
 2566        match self.context_menu.borrow().as_ref() {
 2567            Some(CodeContextMenu::Completions(menu)) => {
 2568                if menu.visible() {
 2569                    key_context.add("menu");
 2570                    key_context.add("showing_completions");
 2571                }
 2572            }
 2573            Some(CodeContextMenu::CodeActions(menu)) => {
 2574                if menu.visible() {
 2575                    key_context.add("menu");
 2576                    key_context.add("showing_code_actions")
 2577                }
 2578            }
 2579            None => {}
 2580        }
 2581
 2582        if self.signature_help_state.has_multiple_signatures() {
 2583            key_context.add("showing_signature_help");
 2584        }
 2585
 2586        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2587        if !self.focus_handle(cx).contains_focused(window, cx)
 2588            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2589        {
 2590            for addon in self.addons.values() {
 2591                addon.extend_key_context(&mut key_context, cx)
 2592            }
 2593        }
 2594
 2595        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2596            if let Some(extension) = singleton_buffer.read(cx).file().and_then(|file| {
 2597                Some(
 2598                    file.full_path(cx)
 2599                        .extension()?
 2600                        .to_string_lossy()
 2601                        .into_owned(),
 2602                )
 2603            }) {
 2604                key_context.set("extension", extension);
 2605            }
 2606        } else {
 2607            key_context.add("multibuffer");
 2608        }
 2609
 2610        if has_active_edit_prediction {
 2611            if self.edit_prediction_in_conflict() {
 2612                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2613            } else {
 2614                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2615                key_context.add("copilot_suggestion");
 2616            }
 2617        }
 2618
 2619        if self.selection_mark_mode {
 2620            key_context.add("selection_mode");
 2621        }
 2622
 2623        let disjoint = self.selections.disjoint_anchors();
 2624        let snapshot = self.snapshot(window, cx);
 2625        let snapshot = snapshot.buffer_snapshot();
 2626        if self.mode == EditorMode::SingleLine
 2627            && let [selection] = disjoint
 2628            && selection.start == selection.end
 2629            && selection.end.to_offset(snapshot) == snapshot.len()
 2630        {
 2631            key_context.add("end_of_input");
 2632        }
 2633
 2634        key_context
 2635    }
 2636
 2637    pub fn last_bounds(&self) -> Option<&Bounds<Pixels>> {
 2638        self.last_bounds.as_ref()
 2639    }
 2640
 2641    fn show_mouse_cursor(&mut self, cx: &mut Context<Self>) {
 2642        if self.mouse_cursor_hidden {
 2643            self.mouse_cursor_hidden = false;
 2644            cx.notify();
 2645        }
 2646    }
 2647
 2648    pub fn hide_mouse_cursor(&mut self, origin: HideMouseCursorOrigin, cx: &mut Context<Self>) {
 2649        let hide_mouse_cursor = match origin {
 2650            HideMouseCursorOrigin::TypingAction => {
 2651                matches!(
 2652                    self.hide_mouse_mode,
 2653                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2654                )
 2655            }
 2656            HideMouseCursorOrigin::MovementAction => {
 2657                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2658            }
 2659        };
 2660        if self.mouse_cursor_hidden != hide_mouse_cursor {
 2661            self.mouse_cursor_hidden = hide_mouse_cursor;
 2662            cx.notify();
 2663        }
 2664    }
 2665
 2666    pub fn edit_prediction_in_conflict(&self) -> bool {
 2667        if !self.show_edit_predictions_in_menu() {
 2668            return false;
 2669        }
 2670
 2671        let showing_completions = self
 2672            .context_menu
 2673            .borrow()
 2674            .as_ref()
 2675            .is_some_and(|context| matches!(context, CodeContextMenu::Completions(_)));
 2676
 2677        showing_completions
 2678            || self.edit_prediction_requires_modifier()
 2679            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2680            // bindings to insert tab characters.
 2681            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2682    }
 2683
 2684    pub fn accept_edit_prediction_keybind(
 2685        &self,
 2686        accept_partial: bool,
 2687        window: &mut Window,
 2688        cx: &mut App,
 2689    ) -> AcceptEditPredictionBinding {
 2690        let key_context = self.key_context_internal(true, window, cx);
 2691        let in_conflict = self.edit_prediction_in_conflict();
 2692
 2693        let bindings = if accept_partial {
 2694            window.bindings_for_action_in_context(&AcceptPartialEditPrediction, key_context)
 2695        } else {
 2696            window.bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2697        };
 2698
 2699        // TODO: if the binding contains multiple keystrokes, display all of them, not
 2700        // just the first one.
 2701        AcceptEditPredictionBinding(bindings.into_iter().rev().find(|binding| {
 2702            !in_conflict
 2703                || binding
 2704                    .keystrokes()
 2705                    .first()
 2706                    .is_some_and(|keystroke| keystroke.modifiers().modified())
 2707        }))
 2708    }
 2709
 2710    pub fn new_file(
 2711        workspace: &mut Workspace,
 2712        _: &workspace::NewFile,
 2713        window: &mut Window,
 2714        cx: &mut Context<Workspace>,
 2715    ) {
 2716        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2717            "Failed to create buffer",
 2718            window,
 2719            cx,
 2720            |e, _, _| match e.error_code() {
 2721                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2722                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2723                e.error_tag("required").unwrap_or("the latest version")
 2724            )),
 2725                _ => None,
 2726            },
 2727        );
 2728    }
 2729
 2730    pub fn new_in_workspace(
 2731        workspace: &mut Workspace,
 2732        window: &mut Window,
 2733        cx: &mut Context<Workspace>,
 2734    ) -> Task<Result<Entity<Editor>>> {
 2735        let project = workspace.project().clone();
 2736        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2737
 2738        cx.spawn_in(window, async move |workspace, cx| {
 2739            let buffer = create.await?;
 2740            workspace.update_in(cx, |workspace, window, cx| {
 2741                let editor =
 2742                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2743                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2744                editor
 2745            })
 2746        })
 2747    }
 2748
 2749    fn new_file_vertical(
 2750        workspace: &mut Workspace,
 2751        _: &workspace::NewFileSplitVertical,
 2752        window: &mut Window,
 2753        cx: &mut Context<Workspace>,
 2754    ) {
 2755        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2756    }
 2757
 2758    fn new_file_horizontal(
 2759        workspace: &mut Workspace,
 2760        _: &workspace::NewFileSplitHorizontal,
 2761        window: &mut Window,
 2762        cx: &mut Context<Workspace>,
 2763    ) {
 2764        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2765    }
 2766
 2767    fn new_file_split(
 2768        workspace: &mut Workspace,
 2769        action: &workspace::NewFileSplit,
 2770        window: &mut Window,
 2771        cx: &mut Context<Workspace>,
 2772    ) {
 2773        Self::new_file_in_direction(workspace, action.0, window, cx)
 2774    }
 2775
 2776    fn new_file_in_direction(
 2777        workspace: &mut Workspace,
 2778        direction: SplitDirection,
 2779        window: &mut Window,
 2780        cx: &mut Context<Workspace>,
 2781    ) {
 2782        let project = workspace.project().clone();
 2783        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2784
 2785        cx.spawn_in(window, async move |workspace, cx| {
 2786            let buffer = create.await?;
 2787            workspace.update_in(cx, move |workspace, window, cx| {
 2788                workspace.split_item(
 2789                    direction,
 2790                    Box::new(
 2791                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2792                    ),
 2793                    window,
 2794                    cx,
 2795                )
 2796            })?;
 2797            anyhow::Ok(())
 2798        })
 2799        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2800            match e.error_code() {
 2801                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2802                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2803                e.error_tag("required").unwrap_or("the latest version")
 2804            )),
 2805                _ => None,
 2806            }
 2807        });
 2808    }
 2809
 2810    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2811        self.leader_id
 2812    }
 2813
 2814    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2815        &self.buffer
 2816    }
 2817
 2818    pub fn project(&self) -> Option<&Entity<Project>> {
 2819        self.project.as_ref()
 2820    }
 2821
 2822    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2823        self.workspace.as_ref()?.0.upgrade()
 2824    }
 2825
 2826    /// Returns the workspace serialization ID if this editor should be serialized.
 2827    fn workspace_serialization_id(&self, _cx: &App) -> Option<WorkspaceId> {
 2828        self.workspace
 2829            .as_ref()
 2830            .filter(|_| self.should_serialize_buffer())
 2831            .and_then(|workspace| workspace.1)
 2832    }
 2833
 2834    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2835        self.buffer().read(cx).title(cx)
 2836    }
 2837
 2838    pub fn snapshot(&self, window: &Window, cx: &mut App) -> EditorSnapshot {
 2839        let git_blame_gutter_max_author_length = self
 2840            .render_git_blame_gutter(cx)
 2841            .then(|| {
 2842                if let Some(blame) = self.blame.as_ref() {
 2843                    let max_author_length =
 2844                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2845                    Some(max_author_length)
 2846                } else {
 2847                    None
 2848                }
 2849            })
 2850            .flatten();
 2851
 2852        EditorSnapshot {
 2853            mode: self.mode.clone(),
 2854            show_gutter: self.show_gutter,
 2855            show_line_numbers: self.show_line_numbers,
 2856            show_git_diff_gutter: self.show_git_diff_gutter,
 2857            show_code_actions: self.show_code_actions,
 2858            show_runnables: self.show_runnables,
 2859            show_breakpoints: self.show_breakpoints,
 2860            git_blame_gutter_max_author_length,
 2861            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2862            placeholder_display_snapshot: self
 2863                .placeholder_display_map
 2864                .as_ref()
 2865                .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx))),
 2866            scroll_anchor: self.scroll_manager.anchor(),
 2867            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2868            is_focused: self.focus_handle.is_focused(window),
 2869            current_line_highlight: self
 2870                .current_line_highlight
 2871                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2872            gutter_hovered: self.gutter_hovered,
 2873        }
 2874    }
 2875
 2876    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2877        self.buffer.read(cx).language_at(point, cx)
 2878    }
 2879
 2880    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2881        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2882    }
 2883
 2884    pub fn active_excerpt(
 2885        &self,
 2886        cx: &App,
 2887    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2888        self.buffer
 2889            .read(cx)
 2890            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2891    }
 2892
 2893    pub fn mode(&self) -> &EditorMode {
 2894        &self.mode
 2895    }
 2896
 2897    pub fn set_mode(&mut self, mode: EditorMode) {
 2898        self.mode = mode;
 2899    }
 2900
 2901    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2902        self.collaboration_hub.as_deref()
 2903    }
 2904
 2905    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2906        self.collaboration_hub = Some(hub);
 2907    }
 2908
 2909    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2910        self.in_project_search = in_project_search;
 2911    }
 2912
 2913    pub fn set_custom_context_menu(
 2914        &mut self,
 2915        f: impl 'static
 2916        + Fn(
 2917            &mut Self,
 2918            DisplayPoint,
 2919            &mut Window,
 2920            &mut Context<Self>,
 2921        ) -> Option<Entity<ui::ContextMenu>>,
 2922    ) {
 2923        self.custom_context_menu = Some(Box::new(f))
 2924    }
 2925
 2926    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 2927        self.completion_provider = provider;
 2928    }
 2929
 2930    #[cfg(any(test, feature = "test-support"))]
 2931    pub fn completion_provider(&self) -> Option<Rc<dyn CompletionProvider>> {
 2932        self.completion_provider.clone()
 2933    }
 2934
 2935    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 2936        self.semantics_provider.clone()
 2937    }
 2938
 2939    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 2940        self.semantics_provider = provider;
 2941    }
 2942
 2943    pub fn set_edit_prediction_provider<T>(
 2944        &mut self,
 2945        provider: Option<Entity<T>>,
 2946        window: &mut Window,
 2947        cx: &mut Context<Self>,
 2948    ) where
 2949        T: EditPredictionProvider,
 2950    {
 2951        self.edit_prediction_provider = provider.map(|provider| RegisteredEditPredictionProvider {
 2952            _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 2953                if this.focus_handle.is_focused(window) {
 2954                    this.update_visible_edit_prediction(window, cx);
 2955                }
 2956            }),
 2957            provider: Arc::new(provider),
 2958        });
 2959        self.update_edit_prediction_settings(cx);
 2960        self.refresh_edit_prediction(false, false, window, cx);
 2961    }
 2962
 2963    pub fn placeholder_text(&self, cx: &mut App) -> Option<String> {
 2964        self.placeholder_display_map
 2965            .as_ref()
 2966            .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx)).text())
 2967    }
 2968
 2969    pub fn set_placeholder_text(
 2970        &mut self,
 2971        placeholder_text: &str,
 2972        window: &mut Window,
 2973        cx: &mut Context<Self>,
 2974    ) {
 2975        let multibuffer = cx
 2976            .new(|cx| MultiBuffer::singleton(cx.new(|cx| Buffer::local(placeholder_text, cx)), cx));
 2977
 2978        let style = window.text_style();
 2979
 2980        self.placeholder_display_map = Some(cx.new(|cx| {
 2981            DisplayMap::new(
 2982                multibuffer,
 2983                style.font(),
 2984                style.font_size.to_pixels(window.rem_size()),
 2985                None,
 2986                FILE_HEADER_HEIGHT,
 2987                MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 2988                Default::default(),
 2989                DiagnosticSeverity::Off,
 2990                cx,
 2991            )
 2992        }));
 2993        cx.notify();
 2994    }
 2995
 2996    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 2997        self.cursor_shape = cursor_shape;
 2998
 2999        // Disrupt blink for immediate user feedback that the cursor shape has changed
 3000        self.blink_manager.update(cx, BlinkManager::show_cursor);
 3001
 3002        cx.notify();
 3003    }
 3004
 3005    pub fn set_current_line_highlight(
 3006        &mut self,
 3007        current_line_highlight: Option<CurrentLineHighlight>,
 3008    ) {
 3009        self.current_line_highlight = current_line_highlight;
 3010    }
 3011
 3012    pub fn range_for_match<T: std::marker::Copy>(
 3013        &self,
 3014        range: &Range<T>,
 3015        collapse: bool,
 3016    ) -> Range<T> {
 3017        if collapse {
 3018            return range.start..range.start;
 3019        }
 3020        range.clone()
 3021    }
 3022
 3023    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 3024        if self.display_map.read(cx).clip_at_line_ends != clip {
 3025            self.display_map
 3026                .update(cx, |map, _| map.clip_at_line_ends = clip);
 3027        }
 3028    }
 3029
 3030    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 3031        self.input_enabled = input_enabled;
 3032    }
 3033
 3034    pub fn set_edit_predictions_hidden_for_vim_mode(
 3035        &mut self,
 3036        hidden: bool,
 3037        window: &mut Window,
 3038        cx: &mut Context<Self>,
 3039    ) {
 3040        if hidden != self.edit_predictions_hidden_for_vim_mode {
 3041            self.edit_predictions_hidden_for_vim_mode = hidden;
 3042            if hidden {
 3043                self.update_visible_edit_prediction(window, cx);
 3044            } else {
 3045                self.refresh_edit_prediction(true, false, window, cx);
 3046            }
 3047        }
 3048    }
 3049
 3050    pub fn set_menu_edit_predictions_policy(&mut self, value: MenuEditPredictionsPolicy) {
 3051        self.menu_edit_predictions_policy = value;
 3052    }
 3053
 3054    pub fn set_autoindent(&mut self, autoindent: bool) {
 3055        if autoindent {
 3056            self.autoindent_mode = Some(AutoindentMode::EachLine);
 3057        } else {
 3058            self.autoindent_mode = None;
 3059        }
 3060    }
 3061
 3062    pub fn read_only(&self, cx: &App) -> bool {
 3063        self.read_only || self.buffer.read(cx).read_only()
 3064    }
 3065
 3066    pub fn set_read_only(&mut self, read_only: bool) {
 3067        self.read_only = read_only;
 3068    }
 3069
 3070    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 3071        self.use_autoclose = autoclose;
 3072    }
 3073
 3074    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 3075        self.use_auto_surround = auto_surround;
 3076    }
 3077
 3078    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 3079        self.auto_replace_emoji_shortcode = auto_replace;
 3080    }
 3081
 3082    pub fn set_should_serialize(&mut self, should_serialize: bool, cx: &App) {
 3083        self.buffer_serialization = should_serialize.then(|| {
 3084            BufferSerialization::new(
 3085                ProjectSettings::get_global(cx)
 3086                    .session
 3087                    .restore_unsaved_buffers,
 3088            )
 3089        })
 3090    }
 3091
 3092    fn should_serialize_buffer(&self) -> bool {
 3093        self.buffer_serialization.is_some()
 3094    }
 3095
 3096    pub fn toggle_edit_predictions(
 3097        &mut self,
 3098        _: &ToggleEditPrediction,
 3099        window: &mut Window,
 3100        cx: &mut Context<Self>,
 3101    ) {
 3102        if self.show_edit_predictions_override.is_some() {
 3103            self.set_show_edit_predictions(None, window, cx);
 3104        } else {
 3105            let show_edit_predictions = !self.edit_predictions_enabled();
 3106            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 3107        }
 3108    }
 3109
 3110    pub fn set_show_edit_predictions(
 3111        &mut self,
 3112        show_edit_predictions: Option<bool>,
 3113        window: &mut Window,
 3114        cx: &mut Context<Self>,
 3115    ) {
 3116        self.show_edit_predictions_override = show_edit_predictions;
 3117        self.update_edit_prediction_settings(cx);
 3118
 3119        if let Some(false) = show_edit_predictions {
 3120            self.discard_edit_prediction(false, cx);
 3121        } else {
 3122            self.refresh_edit_prediction(false, true, window, cx);
 3123        }
 3124    }
 3125
 3126    fn edit_predictions_disabled_in_scope(
 3127        &self,
 3128        buffer: &Entity<Buffer>,
 3129        buffer_position: language::Anchor,
 3130        cx: &App,
 3131    ) -> bool {
 3132        let snapshot = buffer.read(cx).snapshot();
 3133        let settings = snapshot.settings_at(buffer_position, cx);
 3134
 3135        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 3136            return false;
 3137        };
 3138
 3139        scope.override_name().is_some_and(|scope_name| {
 3140            settings
 3141                .edit_predictions_disabled_in
 3142                .iter()
 3143                .any(|s| s == scope_name)
 3144        })
 3145    }
 3146
 3147    pub fn set_use_modal_editing(&mut self, to: bool) {
 3148        self.use_modal_editing = to;
 3149    }
 3150
 3151    pub fn use_modal_editing(&self) -> bool {
 3152        self.use_modal_editing
 3153    }
 3154
 3155    fn selections_did_change(
 3156        &mut self,
 3157        local: bool,
 3158        old_cursor_position: &Anchor,
 3159        effects: SelectionEffects,
 3160        window: &mut Window,
 3161        cx: &mut Context<Self>,
 3162    ) {
 3163        window.invalidate_character_coordinates();
 3164
 3165        // Copy selections to primary selection buffer
 3166        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 3167        if local {
 3168            let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
 3169            let buffer_handle = self.buffer.read(cx).read(cx);
 3170
 3171            let mut text = String::new();
 3172            for (index, selection) in selections.iter().enumerate() {
 3173                let text_for_selection = buffer_handle
 3174                    .text_for_range(selection.start..selection.end)
 3175                    .collect::<String>();
 3176
 3177                text.push_str(&text_for_selection);
 3178                if index != selections.len() - 1 {
 3179                    text.push('\n');
 3180                }
 3181            }
 3182
 3183            if !text.is_empty() {
 3184                cx.write_to_primary(ClipboardItem::new_string(text));
 3185            }
 3186        }
 3187
 3188        let selection_anchors = self.selections.disjoint_anchors_arc();
 3189
 3190        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 3191            self.buffer.update(cx, |buffer, cx| {
 3192                buffer.set_active_selections(
 3193                    &selection_anchors,
 3194                    self.selections.line_mode(),
 3195                    self.cursor_shape,
 3196                    cx,
 3197                )
 3198            });
 3199        }
 3200        let display_map = self
 3201            .display_map
 3202            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3203        let buffer = display_map.buffer_snapshot();
 3204        if self.selections.count() == 1 {
 3205            self.add_selections_state = None;
 3206        }
 3207        self.select_next_state = None;
 3208        self.select_prev_state = None;
 3209        self.select_syntax_node_history.try_clear();
 3210        self.invalidate_autoclose_regions(&selection_anchors, buffer);
 3211        self.snippet_stack.invalidate(&selection_anchors, buffer);
 3212        self.take_rename(false, window, cx);
 3213
 3214        let newest_selection = self.selections.newest_anchor();
 3215        let new_cursor_position = newest_selection.head();
 3216        let selection_start = newest_selection.start;
 3217
 3218        if effects.nav_history.is_none() || effects.nav_history == Some(true) {
 3219            self.push_to_nav_history(
 3220                *old_cursor_position,
 3221                Some(new_cursor_position.to_point(buffer)),
 3222                false,
 3223                effects.nav_history == Some(true),
 3224                cx,
 3225            );
 3226        }
 3227
 3228        if local {
 3229            if let Some(buffer_id) = new_cursor_position.buffer_id {
 3230                self.register_buffer(buffer_id, cx);
 3231            }
 3232
 3233            let mut context_menu = self.context_menu.borrow_mut();
 3234            let completion_menu = match context_menu.as_ref() {
 3235                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 3236                Some(CodeContextMenu::CodeActions(_)) => {
 3237                    *context_menu = None;
 3238                    None
 3239                }
 3240                None => None,
 3241            };
 3242            let completion_position = completion_menu.map(|menu| menu.initial_position);
 3243            drop(context_menu);
 3244
 3245            if effects.completions
 3246                && let Some(completion_position) = completion_position
 3247            {
 3248                let start_offset = selection_start.to_offset(buffer);
 3249                let position_matches = start_offset == completion_position.to_offset(buffer);
 3250                let continue_showing = if position_matches {
 3251                    if self.snippet_stack.is_empty() {
 3252                        buffer.char_kind_before(start_offset, Some(CharScopeContext::Completion))
 3253                            == Some(CharKind::Word)
 3254                    } else {
 3255                        // Snippet choices can be shown even when the cursor is in whitespace.
 3256                        // Dismissing the menu with actions like backspace is handled by
 3257                        // invalidation regions.
 3258                        true
 3259                    }
 3260                } else {
 3261                    false
 3262                };
 3263
 3264                if continue_showing {
 3265                    self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 3266                } else {
 3267                    self.hide_context_menu(window, cx);
 3268                }
 3269            }
 3270
 3271            hide_hover(self, cx);
 3272
 3273            if old_cursor_position.to_display_point(&display_map).row()
 3274                != new_cursor_position.to_display_point(&display_map).row()
 3275            {
 3276                self.available_code_actions.take();
 3277            }
 3278            self.refresh_code_actions(window, cx);
 3279            self.refresh_document_highlights(cx);
 3280            refresh_linked_ranges(self, window, cx);
 3281
 3282            self.refresh_selected_text_highlights(false, window, cx);
 3283            self.refresh_matching_bracket_highlights(window, cx);
 3284            self.update_visible_edit_prediction(window, cx);
 3285            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 3286            self.inline_blame_popover.take();
 3287            if self.git_blame_inline_enabled {
 3288                self.start_inline_blame_timer(window, cx);
 3289            }
 3290        }
 3291
 3292        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 3293        cx.emit(EditorEvent::SelectionsChanged { local });
 3294
 3295        let selections = &self.selections.disjoint_anchors_arc();
 3296        if selections.len() == 1 {
 3297            cx.emit(SearchEvent::ActiveMatchChanged)
 3298        }
 3299        if local && let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 3300            let inmemory_selections = selections
 3301                .iter()
 3302                .map(|s| {
 3303                    text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 3304                        ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 3305                })
 3306                .collect();
 3307            self.update_restoration_data(cx, |data| {
 3308                data.selections = inmemory_selections;
 3309            });
 3310
 3311            if WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
 3312                && let Some(workspace_id) = self.workspace_serialization_id(cx)
 3313            {
 3314                let snapshot = self.buffer().read(cx).snapshot(cx);
 3315                let selections = selections.clone();
 3316                let background_executor = cx.background_executor().clone();
 3317                let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3318                self.serialize_selections = cx.background_spawn(async move {
 3319                    background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3320                    let db_selections = selections
 3321                        .iter()
 3322                        .map(|selection| {
 3323                            (
 3324                                selection.start.to_offset(&snapshot),
 3325                                selection.end.to_offset(&snapshot),
 3326                            )
 3327                        })
 3328                        .collect();
 3329
 3330                    DB.save_editor_selections(editor_id, workspace_id, db_selections)
 3331                        .await
 3332                        .with_context(|| {
 3333                            format!(
 3334                                "persisting editor selections for editor {editor_id}, \
 3335                                workspace {workspace_id:?}"
 3336                            )
 3337                        })
 3338                        .log_err();
 3339                });
 3340            }
 3341        }
 3342
 3343        cx.notify();
 3344    }
 3345
 3346    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 3347        use text::ToOffset as _;
 3348        use text::ToPoint as _;
 3349
 3350        if self.mode.is_minimap()
 3351            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 3352        {
 3353            return;
 3354        }
 3355
 3356        if !self.buffer().read(cx).is_singleton() {
 3357            return;
 3358        }
 3359
 3360        let display_snapshot = self
 3361            .display_map
 3362            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3363        let Some((.., snapshot)) = display_snapshot.buffer_snapshot().as_singleton() else {
 3364            return;
 3365        };
 3366        let inmemory_folds = display_snapshot
 3367            .folds_in_range(0..display_snapshot.buffer_snapshot().len())
 3368            .map(|fold| {
 3369                fold.range.start.text_anchor.to_point(&snapshot)
 3370                    ..fold.range.end.text_anchor.to_point(&snapshot)
 3371            })
 3372            .collect();
 3373        self.update_restoration_data(cx, |data| {
 3374            data.folds = inmemory_folds;
 3375        });
 3376
 3377        let Some(workspace_id) = self.workspace_serialization_id(cx) else {
 3378            return;
 3379        };
 3380        let background_executor = cx.background_executor().clone();
 3381        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3382        let db_folds = display_snapshot
 3383            .folds_in_range(0..display_snapshot.buffer_snapshot().len())
 3384            .map(|fold| {
 3385                (
 3386                    fold.range.start.text_anchor.to_offset(&snapshot),
 3387                    fold.range.end.text_anchor.to_offset(&snapshot),
 3388                )
 3389            })
 3390            .collect();
 3391        self.serialize_folds = cx.background_spawn(async move {
 3392            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3393            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 3394                .await
 3395                .with_context(|| {
 3396                    format!(
 3397                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 3398                    )
 3399                })
 3400                .log_err();
 3401        });
 3402    }
 3403
 3404    pub fn sync_selections(
 3405        &mut self,
 3406        other: Entity<Editor>,
 3407        cx: &mut Context<Self>,
 3408    ) -> gpui::Subscription {
 3409        let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3410        if !other_selections.is_empty() {
 3411            self.selections
 3412                .change_with(&self.display_snapshot(cx), |selections| {
 3413                    selections.select_anchors(other_selections);
 3414                });
 3415        }
 3416
 3417        let other_subscription = cx.subscribe(&other, |this, other, other_evt, cx| {
 3418            if let EditorEvent::SelectionsChanged { local: true } = other_evt {
 3419                let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3420                if other_selections.is_empty() {
 3421                    return;
 3422                }
 3423                let snapshot = this.display_snapshot(cx);
 3424                this.selections.change_with(&snapshot, |selections| {
 3425                    selections.select_anchors(other_selections);
 3426                });
 3427            }
 3428        });
 3429
 3430        let this_subscription = cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| {
 3431            if let EditorEvent::SelectionsChanged { local: true } = this_evt {
 3432                let these_selections = this.selections.disjoint_anchors().to_vec();
 3433                if these_selections.is_empty() {
 3434                    return;
 3435                }
 3436                other.update(cx, |other_editor, cx| {
 3437                    let snapshot = other_editor.display_snapshot(cx);
 3438                    other_editor
 3439                        .selections
 3440                        .change_with(&snapshot, |selections| {
 3441                            selections.select_anchors(these_selections);
 3442                        })
 3443                });
 3444            }
 3445        });
 3446
 3447        Subscription::join(other_subscription, this_subscription)
 3448    }
 3449
 3450    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 3451    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 3452    /// effects of selection change occur at the end of the transaction.
 3453    pub fn change_selections<R>(
 3454        &mut self,
 3455        effects: SelectionEffects,
 3456        window: &mut Window,
 3457        cx: &mut Context<Self>,
 3458        change: impl FnOnce(&mut MutableSelectionsCollection<'_, '_>) -> R,
 3459    ) -> R {
 3460        let snapshot = self.display_snapshot(cx);
 3461        if let Some(state) = &mut self.deferred_selection_effects_state {
 3462            state.effects.scroll = effects.scroll.or(state.effects.scroll);
 3463            state.effects.completions = effects.completions;
 3464            state.effects.nav_history = effects.nav_history.or(state.effects.nav_history);
 3465            let (changed, result) = self.selections.change_with(&snapshot, change);
 3466            state.changed |= changed;
 3467            return result;
 3468        }
 3469        let mut state = DeferredSelectionEffectsState {
 3470            changed: false,
 3471            effects,
 3472            old_cursor_position: self.selections.newest_anchor().head(),
 3473            history_entry: SelectionHistoryEntry {
 3474                selections: self.selections.disjoint_anchors_arc(),
 3475                select_next_state: self.select_next_state.clone(),
 3476                select_prev_state: self.select_prev_state.clone(),
 3477                add_selections_state: self.add_selections_state.clone(),
 3478            },
 3479        };
 3480        let (changed, result) = self.selections.change_with(&snapshot, change);
 3481        state.changed = state.changed || changed;
 3482        if self.defer_selection_effects {
 3483            self.deferred_selection_effects_state = Some(state);
 3484        } else {
 3485            self.apply_selection_effects(state, window, cx);
 3486        }
 3487        result
 3488    }
 3489
 3490    /// Defers the effects of selection change, so that the effects of multiple calls to
 3491    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3492    /// to selection history and the state of popovers based on selection position aren't
 3493    /// erroneously updated.
 3494    pub fn with_selection_effects_deferred<R>(
 3495        &mut self,
 3496        window: &mut Window,
 3497        cx: &mut Context<Self>,
 3498        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3499    ) -> R {
 3500        let already_deferred = self.defer_selection_effects;
 3501        self.defer_selection_effects = true;
 3502        let result = update(self, window, cx);
 3503        if !already_deferred {
 3504            self.defer_selection_effects = false;
 3505            if let Some(state) = self.deferred_selection_effects_state.take() {
 3506                self.apply_selection_effects(state, window, cx);
 3507            }
 3508        }
 3509        result
 3510    }
 3511
 3512    fn apply_selection_effects(
 3513        &mut self,
 3514        state: DeferredSelectionEffectsState,
 3515        window: &mut Window,
 3516        cx: &mut Context<Self>,
 3517    ) {
 3518        if state.changed {
 3519            self.selection_history.push(state.history_entry);
 3520
 3521            if let Some(autoscroll) = state.effects.scroll {
 3522                self.request_autoscroll(autoscroll, cx);
 3523            }
 3524
 3525            let old_cursor_position = &state.old_cursor_position;
 3526
 3527            self.selections_did_change(true, old_cursor_position, state.effects, window, cx);
 3528
 3529            if self.should_open_signature_help_automatically(old_cursor_position, cx) {
 3530                self.show_signature_help(&ShowSignatureHelp, window, cx);
 3531            }
 3532        }
 3533    }
 3534
 3535    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3536    where
 3537        I: IntoIterator<Item = (Range<S>, T)>,
 3538        S: ToOffset,
 3539        T: Into<Arc<str>>,
 3540    {
 3541        if self.read_only(cx) {
 3542            return;
 3543        }
 3544
 3545        self.buffer
 3546            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3547    }
 3548
 3549    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3550    where
 3551        I: IntoIterator<Item = (Range<S>, T)>,
 3552        S: ToOffset,
 3553        T: Into<Arc<str>>,
 3554    {
 3555        if self.read_only(cx) {
 3556            return;
 3557        }
 3558
 3559        self.buffer.update(cx, |buffer, cx| {
 3560            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3561        });
 3562    }
 3563
 3564    pub fn edit_with_block_indent<I, S, T>(
 3565        &mut self,
 3566        edits: I,
 3567        original_indent_columns: Vec<Option<u32>>,
 3568        cx: &mut Context<Self>,
 3569    ) where
 3570        I: IntoIterator<Item = (Range<S>, T)>,
 3571        S: ToOffset,
 3572        T: Into<Arc<str>>,
 3573    {
 3574        if self.read_only(cx) {
 3575            return;
 3576        }
 3577
 3578        self.buffer.update(cx, |buffer, cx| {
 3579            buffer.edit(
 3580                edits,
 3581                Some(AutoindentMode::Block {
 3582                    original_indent_columns,
 3583                }),
 3584                cx,
 3585            )
 3586        });
 3587    }
 3588
 3589    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3590        self.hide_context_menu(window, cx);
 3591
 3592        match phase {
 3593            SelectPhase::Begin {
 3594                position,
 3595                add,
 3596                click_count,
 3597            } => self.begin_selection(position, add, click_count, window, cx),
 3598            SelectPhase::BeginColumnar {
 3599                position,
 3600                goal_column,
 3601                reset,
 3602                mode,
 3603            } => self.begin_columnar_selection(position, goal_column, reset, mode, window, cx),
 3604            SelectPhase::Extend {
 3605                position,
 3606                click_count,
 3607            } => self.extend_selection(position, click_count, window, cx),
 3608            SelectPhase::Update {
 3609                position,
 3610                goal_column,
 3611                scroll_delta,
 3612            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3613            SelectPhase::End => self.end_selection(window, cx),
 3614        }
 3615    }
 3616
 3617    fn extend_selection(
 3618        &mut self,
 3619        position: DisplayPoint,
 3620        click_count: usize,
 3621        window: &mut Window,
 3622        cx: &mut Context<Self>,
 3623    ) {
 3624        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3625        let tail = self.selections.newest::<usize>(&display_map).tail();
 3626        let click_count = click_count.max(match self.selections.select_mode() {
 3627            SelectMode::Character => 1,
 3628            SelectMode::Word(_) => 2,
 3629            SelectMode::Line(_) => 3,
 3630            SelectMode::All => 4,
 3631        });
 3632        self.begin_selection(position, false, click_count, window, cx);
 3633
 3634        let tail_anchor = display_map.buffer_snapshot().anchor_before(tail);
 3635
 3636        let current_selection = match self.selections.select_mode() {
 3637            SelectMode::Character | SelectMode::All => tail_anchor..tail_anchor,
 3638            SelectMode::Word(range) | SelectMode::Line(range) => range.clone(),
 3639        };
 3640
 3641        let mut pending_selection = self
 3642            .selections
 3643            .pending_anchor()
 3644            .cloned()
 3645            .expect("extend_selection not called with pending selection");
 3646
 3647        if pending_selection
 3648            .start
 3649            .cmp(&current_selection.start, display_map.buffer_snapshot())
 3650            == Ordering::Greater
 3651        {
 3652            pending_selection.start = current_selection.start;
 3653        }
 3654        if pending_selection
 3655            .end
 3656            .cmp(&current_selection.end, display_map.buffer_snapshot())
 3657            == Ordering::Less
 3658        {
 3659            pending_selection.end = current_selection.end;
 3660            pending_selection.reversed = true;
 3661        }
 3662
 3663        let mut pending_mode = self.selections.pending_mode().unwrap();
 3664        match &mut pending_mode {
 3665            SelectMode::Word(range) | SelectMode::Line(range) => *range = current_selection,
 3666            _ => {}
 3667        }
 3668
 3669        let effects = if EditorSettings::get_global(cx).autoscroll_on_clicks {
 3670            SelectionEffects::scroll(Autoscroll::fit())
 3671        } else {
 3672            SelectionEffects::no_scroll()
 3673        };
 3674
 3675        self.change_selections(effects, window, cx, |s| {
 3676            s.set_pending(pending_selection.clone(), pending_mode);
 3677            s.set_is_extending(true);
 3678        });
 3679    }
 3680
 3681    fn begin_selection(
 3682        &mut self,
 3683        position: DisplayPoint,
 3684        add: bool,
 3685        click_count: usize,
 3686        window: &mut Window,
 3687        cx: &mut Context<Self>,
 3688    ) {
 3689        if !self.focus_handle.is_focused(window) {
 3690            self.last_focused_descendant = None;
 3691            window.focus(&self.focus_handle);
 3692        }
 3693
 3694        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3695        let buffer = display_map.buffer_snapshot();
 3696        let position = display_map.clip_point(position, Bias::Left);
 3697
 3698        let start;
 3699        let end;
 3700        let mode;
 3701        let mut auto_scroll;
 3702        match click_count {
 3703            1 => {
 3704                start = buffer.anchor_before(position.to_point(&display_map));
 3705                end = start;
 3706                mode = SelectMode::Character;
 3707                auto_scroll = true;
 3708            }
 3709            2 => {
 3710                let position = display_map
 3711                    .clip_point(position, Bias::Left)
 3712                    .to_offset(&display_map, Bias::Left);
 3713                let (range, _) = buffer.surrounding_word(position, None);
 3714                start = buffer.anchor_before(range.start);
 3715                end = buffer.anchor_before(range.end);
 3716                mode = SelectMode::Word(start..end);
 3717                auto_scroll = true;
 3718            }
 3719            3 => {
 3720                let position = display_map
 3721                    .clip_point(position, Bias::Left)
 3722                    .to_point(&display_map);
 3723                let line_start = display_map.prev_line_boundary(position).0;
 3724                let next_line_start = buffer.clip_point(
 3725                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3726                    Bias::Left,
 3727                );
 3728                start = buffer.anchor_before(line_start);
 3729                end = buffer.anchor_before(next_line_start);
 3730                mode = SelectMode::Line(start..end);
 3731                auto_scroll = true;
 3732            }
 3733            _ => {
 3734                start = buffer.anchor_before(0);
 3735                end = buffer.anchor_before(buffer.len());
 3736                mode = SelectMode::All;
 3737                auto_scroll = false;
 3738            }
 3739        }
 3740        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3741
 3742        let point_to_delete: Option<usize> = {
 3743            let selected_points: Vec<Selection<Point>> =
 3744                self.selections.disjoint_in_range(start..end, &display_map);
 3745
 3746            if !add || click_count > 1 {
 3747                None
 3748            } else if !selected_points.is_empty() {
 3749                Some(selected_points[0].id)
 3750            } else {
 3751                let clicked_point_already_selected =
 3752                    self.selections.disjoint_anchors().iter().find(|selection| {
 3753                        selection.start.to_point(buffer) == start.to_point(buffer)
 3754                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3755                    });
 3756
 3757                clicked_point_already_selected.map(|selection| selection.id)
 3758            }
 3759        };
 3760
 3761        let selections_count = self.selections.count();
 3762        let effects = if auto_scroll {
 3763            SelectionEffects::default()
 3764        } else {
 3765            SelectionEffects::no_scroll()
 3766        };
 3767
 3768        self.change_selections(effects, window, cx, |s| {
 3769            if let Some(point_to_delete) = point_to_delete {
 3770                s.delete(point_to_delete);
 3771
 3772                if selections_count == 1 {
 3773                    s.set_pending_anchor_range(start..end, mode);
 3774                }
 3775            } else {
 3776                if !add {
 3777                    s.clear_disjoint();
 3778                }
 3779
 3780                s.set_pending_anchor_range(start..end, mode);
 3781            }
 3782        });
 3783    }
 3784
 3785    fn begin_columnar_selection(
 3786        &mut self,
 3787        position: DisplayPoint,
 3788        goal_column: u32,
 3789        reset: bool,
 3790        mode: ColumnarMode,
 3791        window: &mut Window,
 3792        cx: &mut Context<Self>,
 3793    ) {
 3794        if !self.focus_handle.is_focused(window) {
 3795            self.last_focused_descendant = None;
 3796            window.focus(&self.focus_handle);
 3797        }
 3798
 3799        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3800
 3801        if reset {
 3802            let pointer_position = display_map
 3803                .buffer_snapshot()
 3804                .anchor_before(position.to_point(&display_map));
 3805
 3806            self.change_selections(
 3807                SelectionEffects::scroll(Autoscroll::newest()),
 3808                window,
 3809                cx,
 3810                |s| {
 3811                    s.clear_disjoint();
 3812                    s.set_pending_anchor_range(
 3813                        pointer_position..pointer_position,
 3814                        SelectMode::Character,
 3815                    );
 3816                },
 3817            );
 3818        };
 3819
 3820        let tail = self.selections.newest::<Point>(&display_map).tail();
 3821        let selection_anchor = display_map.buffer_snapshot().anchor_before(tail);
 3822        self.columnar_selection_state = match mode {
 3823            ColumnarMode::FromMouse => Some(ColumnarSelectionState::FromMouse {
 3824                selection_tail: selection_anchor,
 3825                display_point: if reset {
 3826                    if position.column() != goal_column {
 3827                        Some(DisplayPoint::new(position.row(), goal_column))
 3828                    } else {
 3829                        None
 3830                    }
 3831                } else {
 3832                    None
 3833                },
 3834            }),
 3835            ColumnarMode::FromSelection => Some(ColumnarSelectionState::FromSelection {
 3836                selection_tail: selection_anchor,
 3837            }),
 3838        };
 3839
 3840        if !reset {
 3841            self.select_columns(position, goal_column, &display_map, window, cx);
 3842        }
 3843    }
 3844
 3845    fn update_selection(
 3846        &mut self,
 3847        position: DisplayPoint,
 3848        goal_column: u32,
 3849        scroll_delta: gpui::Point<f32>,
 3850        window: &mut Window,
 3851        cx: &mut Context<Self>,
 3852    ) {
 3853        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3854
 3855        if self.columnar_selection_state.is_some() {
 3856            self.select_columns(position, goal_column, &display_map, window, cx);
 3857        } else if let Some(mut pending) = self.selections.pending_anchor().cloned() {
 3858            let buffer = display_map.buffer_snapshot();
 3859            let head;
 3860            let tail;
 3861            let mode = self.selections.pending_mode().unwrap();
 3862            match &mode {
 3863                SelectMode::Character => {
 3864                    head = position.to_point(&display_map);
 3865                    tail = pending.tail().to_point(buffer);
 3866                }
 3867                SelectMode::Word(original_range) => {
 3868                    let offset = display_map
 3869                        .clip_point(position, Bias::Left)
 3870                        .to_offset(&display_map, Bias::Left);
 3871                    let original_range = original_range.to_offset(buffer);
 3872
 3873                    let head_offset = if buffer.is_inside_word(offset, None)
 3874                        || original_range.contains(&offset)
 3875                    {
 3876                        let (word_range, _) = buffer.surrounding_word(offset, None);
 3877                        if word_range.start < original_range.start {
 3878                            word_range.start
 3879                        } else {
 3880                            word_range.end
 3881                        }
 3882                    } else {
 3883                        offset
 3884                    };
 3885
 3886                    head = head_offset.to_point(buffer);
 3887                    if head_offset <= original_range.start {
 3888                        tail = original_range.end.to_point(buffer);
 3889                    } else {
 3890                        tail = original_range.start.to_point(buffer);
 3891                    }
 3892                }
 3893                SelectMode::Line(original_range) => {
 3894                    let original_range = original_range.to_point(display_map.buffer_snapshot());
 3895
 3896                    let position = display_map
 3897                        .clip_point(position, Bias::Left)
 3898                        .to_point(&display_map);
 3899                    let line_start = display_map.prev_line_boundary(position).0;
 3900                    let next_line_start = buffer.clip_point(
 3901                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3902                        Bias::Left,
 3903                    );
 3904
 3905                    if line_start < original_range.start {
 3906                        head = line_start
 3907                    } else {
 3908                        head = next_line_start
 3909                    }
 3910
 3911                    if head <= original_range.start {
 3912                        tail = original_range.end;
 3913                    } else {
 3914                        tail = original_range.start;
 3915                    }
 3916                }
 3917                SelectMode::All => {
 3918                    return;
 3919                }
 3920            };
 3921
 3922            if head < tail {
 3923                pending.start = buffer.anchor_before(head);
 3924                pending.end = buffer.anchor_before(tail);
 3925                pending.reversed = true;
 3926            } else {
 3927                pending.start = buffer.anchor_before(tail);
 3928                pending.end = buffer.anchor_before(head);
 3929                pending.reversed = false;
 3930            }
 3931
 3932            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3933                s.set_pending(pending.clone(), mode);
 3934            });
 3935        } else {
 3936            log::error!("update_selection dispatched with no pending selection");
 3937            return;
 3938        }
 3939
 3940        self.apply_scroll_delta(scroll_delta, window, cx);
 3941        cx.notify();
 3942    }
 3943
 3944    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3945        self.columnar_selection_state.take();
 3946        if let Some(pending_mode) = self.selections.pending_mode() {
 3947            let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
 3948            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3949                s.select(selections);
 3950                s.clear_pending();
 3951                if s.is_extending() {
 3952                    s.set_is_extending(false);
 3953                } else {
 3954                    s.set_select_mode(pending_mode);
 3955                }
 3956            });
 3957        }
 3958    }
 3959
 3960    fn select_columns(
 3961        &mut self,
 3962        head: DisplayPoint,
 3963        goal_column: u32,
 3964        display_map: &DisplaySnapshot,
 3965        window: &mut Window,
 3966        cx: &mut Context<Self>,
 3967    ) {
 3968        let Some(columnar_state) = self.columnar_selection_state.as_ref() else {
 3969            return;
 3970        };
 3971
 3972        let tail = match columnar_state {
 3973            ColumnarSelectionState::FromMouse {
 3974                selection_tail,
 3975                display_point,
 3976            } => display_point.unwrap_or_else(|| selection_tail.to_display_point(display_map)),
 3977            ColumnarSelectionState::FromSelection { selection_tail } => {
 3978                selection_tail.to_display_point(display_map)
 3979            }
 3980        };
 3981
 3982        let start_row = cmp::min(tail.row(), head.row());
 3983        let end_row = cmp::max(tail.row(), head.row());
 3984        let start_column = cmp::min(tail.column(), goal_column);
 3985        let end_column = cmp::max(tail.column(), goal_column);
 3986        let reversed = start_column < tail.column();
 3987
 3988        let selection_ranges = (start_row.0..=end_row.0)
 3989            .map(DisplayRow)
 3990            .filter_map(|row| {
 3991                if (matches!(columnar_state, ColumnarSelectionState::FromMouse { .. })
 3992                    || start_column <= display_map.line_len(row))
 3993                    && !display_map.is_block_line(row)
 3994                {
 3995                    let start = display_map
 3996                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 3997                        .to_point(display_map);
 3998                    let end = display_map
 3999                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 4000                        .to_point(display_map);
 4001                    if reversed {
 4002                        Some(end..start)
 4003                    } else {
 4004                        Some(start..end)
 4005                    }
 4006                } else {
 4007                    None
 4008                }
 4009            })
 4010            .collect::<Vec<_>>();
 4011        if selection_ranges.is_empty() {
 4012            return;
 4013        }
 4014
 4015        let ranges = match columnar_state {
 4016            ColumnarSelectionState::FromMouse { .. } => {
 4017                let mut non_empty_ranges = selection_ranges
 4018                    .iter()
 4019                    .filter(|selection_range| selection_range.start != selection_range.end)
 4020                    .peekable();
 4021                if non_empty_ranges.peek().is_some() {
 4022                    non_empty_ranges.cloned().collect()
 4023                } else {
 4024                    selection_ranges
 4025                }
 4026            }
 4027            _ => selection_ranges,
 4028        };
 4029
 4030        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 4031            s.select_ranges(ranges);
 4032        });
 4033        cx.notify();
 4034    }
 4035
 4036    pub fn has_non_empty_selection(&self, snapshot: &DisplaySnapshot) -> bool {
 4037        self.selections
 4038            .all_adjusted(snapshot)
 4039            .iter()
 4040            .any(|selection| !selection.is_empty())
 4041    }
 4042
 4043    pub fn has_pending_nonempty_selection(&self) -> bool {
 4044        let pending_nonempty_selection = match self.selections.pending_anchor() {
 4045            Some(Selection { start, end, .. }) => start != end,
 4046            None => false,
 4047        };
 4048
 4049        pending_nonempty_selection
 4050            || (self.columnar_selection_state.is_some()
 4051                && self.selections.disjoint_anchors().len() > 1)
 4052    }
 4053
 4054    pub fn has_pending_selection(&self) -> bool {
 4055        self.selections.pending_anchor().is_some() || self.columnar_selection_state.is_some()
 4056    }
 4057
 4058    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 4059        self.selection_mark_mode = false;
 4060        self.selection_drag_state = SelectionDragState::None;
 4061
 4062        if self.clear_expanded_diff_hunks(cx) {
 4063            cx.notify();
 4064            return;
 4065        }
 4066        if self.dismiss_menus_and_popups(true, window, cx) {
 4067            return;
 4068        }
 4069
 4070        if self.mode.is_full()
 4071            && self.change_selections(Default::default(), window, cx, |s| s.try_cancel())
 4072        {
 4073            return;
 4074        }
 4075
 4076        cx.propagate();
 4077    }
 4078
 4079    pub fn dismiss_menus_and_popups(
 4080        &mut self,
 4081        is_user_requested: bool,
 4082        window: &mut Window,
 4083        cx: &mut Context<Self>,
 4084    ) -> bool {
 4085        if self.take_rename(false, window, cx).is_some() {
 4086            return true;
 4087        }
 4088
 4089        if self.hide_blame_popover(true, cx) {
 4090            return true;
 4091        }
 4092
 4093        if hide_hover(self, cx) {
 4094            return true;
 4095        }
 4096
 4097        if self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape) {
 4098            return true;
 4099        }
 4100
 4101        if self.hide_context_menu(window, cx).is_some() {
 4102            return true;
 4103        }
 4104
 4105        if self.mouse_context_menu.take().is_some() {
 4106            return true;
 4107        }
 4108
 4109        if is_user_requested && self.discard_edit_prediction(true, cx) {
 4110            return true;
 4111        }
 4112
 4113        if self.snippet_stack.pop().is_some() {
 4114            return true;
 4115        }
 4116
 4117        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 4118            self.dismiss_diagnostics(cx);
 4119            return true;
 4120        }
 4121
 4122        false
 4123    }
 4124
 4125    fn linked_editing_ranges_for(
 4126        &self,
 4127        selection: Range<text::Anchor>,
 4128        cx: &App,
 4129    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 4130        if self.linked_edit_ranges.is_empty() {
 4131            return None;
 4132        }
 4133        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 4134            selection.end.buffer_id.and_then(|end_buffer_id| {
 4135                if selection.start.buffer_id != Some(end_buffer_id) {
 4136                    return None;
 4137                }
 4138                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 4139                let snapshot = buffer.read(cx).snapshot();
 4140                self.linked_edit_ranges
 4141                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 4142                    .map(|ranges| (ranges, snapshot, buffer))
 4143            })?;
 4144        use text::ToOffset as TO;
 4145        // find offset from the start of current range to current cursor position
 4146        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 4147
 4148        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 4149        let start_difference = start_offset - start_byte_offset;
 4150        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 4151        let end_difference = end_offset - start_byte_offset;
 4152        // Current range has associated linked ranges.
 4153        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4154        for range in linked_ranges.iter() {
 4155            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 4156            let end_offset = start_offset + end_difference;
 4157            let start_offset = start_offset + start_difference;
 4158            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 4159                continue;
 4160            }
 4161            if self.selections.disjoint_anchor_ranges().any(|s| {
 4162                if s.start.buffer_id != selection.start.buffer_id
 4163                    || s.end.buffer_id != selection.end.buffer_id
 4164                {
 4165                    return false;
 4166                }
 4167                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 4168                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 4169            }) {
 4170                continue;
 4171            }
 4172            let start = buffer_snapshot.anchor_after(start_offset);
 4173            let end = buffer_snapshot.anchor_after(end_offset);
 4174            linked_edits
 4175                .entry(buffer.clone())
 4176                .or_default()
 4177                .push(start..end);
 4178        }
 4179        Some(linked_edits)
 4180    }
 4181
 4182    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4183        let text: Arc<str> = text.into();
 4184
 4185        if self.read_only(cx) {
 4186            return;
 4187        }
 4188
 4189        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4190
 4191        let selections = self.selections.all_adjusted(&self.display_snapshot(cx));
 4192        let mut bracket_inserted = false;
 4193        let mut edits = Vec::new();
 4194        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4195        let mut new_selections = Vec::with_capacity(selections.len());
 4196        let mut new_autoclose_regions = Vec::new();
 4197        let snapshot = self.buffer.read(cx).read(cx);
 4198        let mut clear_linked_edit_ranges = false;
 4199
 4200        for (selection, autoclose_region) in
 4201            self.selections_with_autoclose_regions(selections, &snapshot)
 4202        {
 4203            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 4204                // Determine if the inserted text matches the opening or closing
 4205                // bracket of any of this language's bracket pairs.
 4206                let mut bracket_pair = None;
 4207                let mut is_bracket_pair_start = false;
 4208                let mut is_bracket_pair_end = false;
 4209                if !text.is_empty() {
 4210                    let mut bracket_pair_matching_end = None;
 4211                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 4212                    //  and they are removing the character that triggered IME popup.
 4213                    for (pair, enabled) in scope.brackets() {
 4214                        if !pair.close && !pair.surround {
 4215                            continue;
 4216                        }
 4217
 4218                        if enabled && pair.start.ends_with(text.as_ref()) {
 4219                            let prefix_len = pair.start.len() - text.len();
 4220                            let preceding_text_matches_prefix = prefix_len == 0
 4221                                || (selection.start.column >= (prefix_len as u32)
 4222                                    && snapshot.contains_str_at(
 4223                                        Point::new(
 4224                                            selection.start.row,
 4225                                            selection.start.column - (prefix_len as u32),
 4226                                        ),
 4227                                        &pair.start[..prefix_len],
 4228                                    ));
 4229                            if preceding_text_matches_prefix {
 4230                                bracket_pair = Some(pair.clone());
 4231                                is_bracket_pair_start = true;
 4232                                break;
 4233                            }
 4234                        }
 4235                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 4236                        {
 4237                            // take first bracket pair matching end, but don't break in case a later bracket
 4238                            // pair matches start
 4239                            bracket_pair_matching_end = Some(pair.clone());
 4240                        }
 4241                    }
 4242                    if let Some(end) = bracket_pair_matching_end
 4243                        && bracket_pair.is_none()
 4244                    {
 4245                        bracket_pair = Some(end);
 4246                        is_bracket_pair_end = true;
 4247                    }
 4248                }
 4249
 4250                if let Some(bracket_pair) = bracket_pair {
 4251                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 4252                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 4253                    let auto_surround =
 4254                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 4255                    if selection.is_empty() {
 4256                        if is_bracket_pair_start {
 4257                            // If the inserted text is a suffix of an opening bracket and the
 4258                            // selection is preceded by the rest of the opening bracket, then
 4259                            // insert the closing bracket.
 4260                            let following_text_allows_autoclose = snapshot
 4261                                .chars_at(selection.start)
 4262                                .next()
 4263                                .is_none_or(|c| scope.should_autoclose_before(c));
 4264
 4265                            let preceding_text_allows_autoclose = selection.start.column == 0
 4266                                || snapshot
 4267                                    .reversed_chars_at(selection.start)
 4268                                    .next()
 4269                                    .is_none_or(|c| {
 4270                                        bracket_pair.start != bracket_pair.end
 4271                                            || !snapshot
 4272                                                .char_classifier_at(selection.start)
 4273                                                .is_word(c)
 4274                                    });
 4275
 4276                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 4277                                && bracket_pair.start.len() == 1
 4278                            {
 4279                                let target = bracket_pair.start.chars().next().unwrap();
 4280                                let current_line_count = snapshot
 4281                                    .reversed_chars_at(selection.start)
 4282                                    .take_while(|&c| c != '\n')
 4283                                    .filter(|&c| c == target)
 4284                                    .count();
 4285                                current_line_count % 2 == 1
 4286                            } else {
 4287                                false
 4288                            };
 4289
 4290                            if autoclose
 4291                                && bracket_pair.close
 4292                                && following_text_allows_autoclose
 4293                                && preceding_text_allows_autoclose
 4294                                && !is_closing_quote
 4295                            {
 4296                                let anchor = snapshot.anchor_before(selection.end);
 4297                                new_selections.push((selection.map(|_| anchor), text.len()));
 4298                                new_autoclose_regions.push((
 4299                                    anchor,
 4300                                    text.len(),
 4301                                    selection.id,
 4302                                    bracket_pair.clone(),
 4303                                ));
 4304                                edits.push((
 4305                                    selection.range(),
 4306                                    format!("{}{}", text, bracket_pair.end).into(),
 4307                                ));
 4308                                bracket_inserted = true;
 4309                                continue;
 4310                            }
 4311                        }
 4312
 4313                        if let Some(region) = autoclose_region {
 4314                            // If the selection is followed by an auto-inserted closing bracket,
 4315                            // then don't insert that closing bracket again; just move the selection
 4316                            // past the closing bracket.
 4317                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 4318                                && text.as_ref() == region.pair.end.as_str()
 4319                                && snapshot.contains_str_at(region.range.end, text.as_ref());
 4320                            if should_skip {
 4321                                let anchor = snapshot.anchor_after(selection.end);
 4322                                new_selections
 4323                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 4324                                continue;
 4325                            }
 4326                        }
 4327
 4328                        let always_treat_brackets_as_autoclosed = snapshot
 4329                            .language_settings_at(selection.start, cx)
 4330                            .always_treat_brackets_as_autoclosed;
 4331                        if always_treat_brackets_as_autoclosed
 4332                            && is_bracket_pair_end
 4333                            && snapshot.contains_str_at(selection.end, text.as_ref())
 4334                        {
 4335                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 4336                            // and the inserted text is a closing bracket and the selection is followed
 4337                            // by the closing bracket then move the selection past the closing bracket.
 4338                            let anchor = snapshot.anchor_after(selection.end);
 4339                            new_selections.push((selection.map(|_| anchor), text.len()));
 4340                            continue;
 4341                        }
 4342                    }
 4343                    // If an opening bracket is 1 character long and is typed while
 4344                    // text is selected, then surround that text with the bracket pair.
 4345                    else if auto_surround
 4346                        && bracket_pair.surround
 4347                        && is_bracket_pair_start
 4348                        && bracket_pair.start.chars().count() == 1
 4349                    {
 4350                        edits.push((selection.start..selection.start, text.clone()));
 4351                        edits.push((
 4352                            selection.end..selection.end,
 4353                            bracket_pair.end.as_str().into(),
 4354                        ));
 4355                        bracket_inserted = true;
 4356                        new_selections.push((
 4357                            Selection {
 4358                                id: selection.id,
 4359                                start: snapshot.anchor_after(selection.start),
 4360                                end: snapshot.anchor_before(selection.end),
 4361                                reversed: selection.reversed,
 4362                                goal: selection.goal,
 4363                            },
 4364                            0,
 4365                        ));
 4366                        continue;
 4367                    }
 4368                }
 4369            }
 4370
 4371            if self.auto_replace_emoji_shortcode
 4372                && selection.is_empty()
 4373                && text.as_ref().ends_with(':')
 4374                && let Some(possible_emoji_short_code) =
 4375                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 4376                && !possible_emoji_short_code.is_empty()
 4377                && let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code)
 4378            {
 4379                let emoji_shortcode_start = Point::new(
 4380                    selection.start.row,
 4381                    selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 4382                );
 4383
 4384                // Remove shortcode from buffer
 4385                edits.push((
 4386                    emoji_shortcode_start..selection.start,
 4387                    "".to_string().into(),
 4388                ));
 4389                new_selections.push((
 4390                    Selection {
 4391                        id: selection.id,
 4392                        start: snapshot.anchor_after(emoji_shortcode_start),
 4393                        end: snapshot.anchor_before(selection.start),
 4394                        reversed: selection.reversed,
 4395                        goal: selection.goal,
 4396                    },
 4397                    0,
 4398                ));
 4399
 4400                // Insert emoji
 4401                let selection_start_anchor = snapshot.anchor_after(selection.start);
 4402                new_selections.push((selection.map(|_| selection_start_anchor), 0));
 4403                edits.push((selection.start..selection.end, emoji.to_string().into()));
 4404
 4405                continue;
 4406            }
 4407
 4408            // If not handling any auto-close operation, then just replace the selected
 4409            // text with the given input and move the selection to the end of the
 4410            // newly inserted text.
 4411            let anchor = snapshot.anchor_after(selection.end);
 4412            if !self.linked_edit_ranges.is_empty() {
 4413                let start_anchor = snapshot.anchor_before(selection.start);
 4414
 4415                let is_word_char = text.chars().next().is_none_or(|char| {
 4416                    let classifier = snapshot
 4417                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 4418                        .scope_context(Some(CharScopeContext::LinkedEdit));
 4419                    classifier.is_word(char)
 4420                });
 4421
 4422                if is_word_char {
 4423                    if let Some(ranges) = self
 4424                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 4425                    {
 4426                        for (buffer, edits) in ranges {
 4427                            linked_edits
 4428                                .entry(buffer.clone())
 4429                                .or_default()
 4430                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 4431                        }
 4432                    }
 4433                } else {
 4434                    clear_linked_edit_ranges = true;
 4435                }
 4436            }
 4437
 4438            new_selections.push((selection.map(|_| anchor), 0));
 4439            edits.push((selection.start..selection.end, text.clone()));
 4440        }
 4441
 4442        drop(snapshot);
 4443
 4444        self.transact(window, cx, |this, window, cx| {
 4445            if clear_linked_edit_ranges {
 4446                this.linked_edit_ranges.clear();
 4447            }
 4448            let initial_buffer_versions =
 4449                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 4450
 4451            this.buffer.update(cx, |buffer, cx| {
 4452                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 4453            });
 4454            for (buffer, edits) in linked_edits {
 4455                buffer.update(cx, |buffer, cx| {
 4456                    let snapshot = buffer.snapshot();
 4457                    let edits = edits
 4458                        .into_iter()
 4459                        .map(|(range, text)| {
 4460                            use text::ToPoint as TP;
 4461                            let end_point = TP::to_point(&range.end, &snapshot);
 4462                            let start_point = TP::to_point(&range.start, &snapshot);
 4463                            (start_point..end_point, text)
 4464                        })
 4465                        .sorted_by_key(|(range, _)| range.start);
 4466                    buffer.edit(edits, None, cx);
 4467                })
 4468            }
 4469            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 4470            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 4471            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 4472            let new_selections =
 4473                resolve_selections_wrapping_blocks::<usize, _>(new_anchor_selections, &map)
 4474                    .zip(new_selection_deltas)
 4475                    .map(|(selection, delta)| Selection {
 4476                        id: selection.id,
 4477                        start: selection.start + delta,
 4478                        end: selection.end + delta,
 4479                        reversed: selection.reversed,
 4480                        goal: SelectionGoal::None,
 4481                    })
 4482                    .collect::<Vec<_>>();
 4483
 4484            let mut i = 0;
 4485            for (position, delta, selection_id, pair) in new_autoclose_regions {
 4486                let position = position.to_offset(map.buffer_snapshot()) + delta;
 4487                let start = map.buffer_snapshot().anchor_before(position);
 4488                let end = map.buffer_snapshot().anchor_after(position);
 4489                while let Some(existing_state) = this.autoclose_regions.get(i) {
 4490                    match existing_state
 4491                        .range
 4492                        .start
 4493                        .cmp(&start, map.buffer_snapshot())
 4494                    {
 4495                        Ordering::Less => i += 1,
 4496                        Ordering::Greater => break,
 4497                        Ordering::Equal => {
 4498                            match end.cmp(&existing_state.range.end, map.buffer_snapshot()) {
 4499                                Ordering::Less => i += 1,
 4500                                Ordering::Equal => break,
 4501                                Ordering::Greater => break,
 4502                            }
 4503                        }
 4504                    }
 4505                }
 4506                this.autoclose_regions.insert(
 4507                    i,
 4508                    AutocloseRegion {
 4509                        selection_id,
 4510                        range: start..end,
 4511                        pair,
 4512                    },
 4513                );
 4514            }
 4515
 4516            let had_active_edit_prediction = this.has_active_edit_prediction();
 4517            this.change_selections(
 4518                SelectionEffects::scroll(Autoscroll::fit()).completions(false),
 4519                window,
 4520                cx,
 4521                |s| s.select(new_selections),
 4522            );
 4523
 4524            if !bracket_inserted
 4525                && let Some(on_type_format_task) =
 4526                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 4527            {
 4528                on_type_format_task.detach_and_log_err(cx);
 4529            }
 4530
 4531            let editor_settings = EditorSettings::get_global(cx);
 4532            if bracket_inserted
 4533                && (editor_settings.auto_signature_help
 4534                    || editor_settings.show_signature_help_after_edits)
 4535            {
 4536                this.show_signature_help(&ShowSignatureHelp, window, cx);
 4537            }
 4538
 4539            let trigger_in_words =
 4540                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
 4541            if this.hard_wrap.is_some() {
 4542                let latest: Range<Point> = this.selections.newest(&map).range();
 4543                if latest.is_empty()
 4544                    && this
 4545                        .buffer()
 4546                        .read(cx)
 4547                        .snapshot(cx)
 4548                        .line_len(MultiBufferRow(latest.start.row))
 4549                        == latest.start.column
 4550                {
 4551                    this.rewrap_impl(
 4552                        RewrapOptions {
 4553                            override_language_settings: true,
 4554                            preserve_existing_whitespace: true,
 4555                        },
 4556                        cx,
 4557                    )
 4558                }
 4559            }
 4560            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4561            refresh_linked_ranges(this, window, cx);
 4562            this.refresh_edit_prediction(true, false, window, cx);
 4563            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4564        });
 4565    }
 4566
 4567    fn find_possible_emoji_shortcode_at_position(
 4568        snapshot: &MultiBufferSnapshot,
 4569        position: Point,
 4570    ) -> Option<String> {
 4571        let mut chars = Vec::new();
 4572        let mut found_colon = false;
 4573        for char in snapshot.reversed_chars_at(position).take(100) {
 4574            // Found a possible emoji shortcode in the middle of the buffer
 4575            if found_colon {
 4576                if char.is_whitespace() {
 4577                    chars.reverse();
 4578                    return Some(chars.iter().collect());
 4579                }
 4580                // If the previous character is not a whitespace, we are in the middle of a word
 4581                // and we only want to complete the shortcode if the word is made up of other emojis
 4582                let mut containing_word = String::new();
 4583                for ch in snapshot
 4584                    .reversed_chars_at(position)
 4585                    .skip(chars.len() + 1)
 4586                    .take(100)
 4587                {
 4588                    if ch.is_whitespace() {
 4589                        break;
 4590                    }
 4591                    containing_word.push(ch);
 4592                }
 4593                let containing_word = containing_word.chars().rev().collect::<String>();
 4594                if util::word_consists_of_emojis(containing_word.as_str()) {
 4595                    chars.reverse();
 4596                    return Some(chars.iter().collect());
 4597                }
 4598            }
 4599
 4600            if char.is_whitespace() || !char.is_ascii() {
 4601                return None;
 4602            }
 4603            if char == ':' {
 4604                found_colon = true;
 4605            } else {
 4606                chars.push(char);
 4607            }
 4608        }
 4609        // Found a possible emoji shortcode at the beginning of the buffer
 4610        chars.reverse();
 4611        Some(chars.iter().collect())
 4612    }
 4613
 4614    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4615        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4616        self.transact(window, cx, |this, window, cx| {
 4617            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4618                let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
 4619                let multi_buffer = this.buffer.read(cx);
 4620                let buffer = multi_buffer.snapshot(cx);
 4621                selections
 4622                    .iter()
 4623                    .map(|selection| {
 4624                        let start_point = selection.start.to_point(&buffer);
 4625                        let mut existing_indent =
 4626                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4627                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4628                        let start = selection.start;
 4629                        let end = selection.end;
 4630                        let selection_is_empty = start == end;
 4631                        let language_scope = buffer.language_scope_at(start);
 4632                        let (
 4633                            comment_delimiter,
 4634                            doc_delimiter,
 4635                            insert_extra_newline,
 4636                            indent_on_newline,
 4637                            indent_on_extra_newline,
 4638                        ) = if let Some(language) = &language_scope {
 4639                            let mut insert_extra_newline =
 4640                                insert_extra_newline_brackets(&buffer, start..end, language)
 4641                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 4642
 4643                            // Comment extension on newline is allowed only for cursor selections
 4644                            let comment_delimiter = maybe!({
 4645                                if !selection_is_empty {
 4646                                    return None;
 4647                                }
 4648
 4649                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4650                                    return None;
 4651                                }
 4652
 4653                                let delimiters = language.line_comment_prefixes();
 4654                                let max_len_of_delimiter =
 4655                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 4656                                let (snapshot, range) =
 4657                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4658
 4659                                let num_of_whitespaces = snapshot
 4660                                    .chars_for_range(range.clone())
 4661                                    .take_while(|c| c.is_whitespace())
 4662                                    .count();
 4663                                let comment_candidate = snapshot
 4664                                    .chars_for_range(range.clone())
 4665                                    .skip(num_of_whitespaces)
 4666                                    .take(max_len_of_delimiter)
 4667                                    .collect::<String>();
 4668                                let (delimiter, trimmed_len) = delimiters
 4669                                    .iter()
 4670                                    .filter_map(|delimiter| {
 4671                                        let prefix = delimiter.trim_end();
 4672                                        if comment_candidate.starts_with(prefix) {
 4673                                            Some((delimiter, prefix.len()))
 4674                                        } else {
 4675                                            None
 4676                                        }
 4677                                    })
 4678                                    .max_by_key(|(_, len)| *len)?;
 4679
 4680                                if let Some(BlockCommentConfig {
 4681                                    start: block_start, ..
 4682                                }) = language.block_comment()
 4683                                {
 4684                                    let block_start_trimmed = block_start.trim_end();
 4685                                    if block_start_trimmed.starts_with(delimiter.trim_end()) {
 4686                                        let line_content = snapshot
 4687                                            .chars_for_range(range)
 4688                                            .skip(num_of_whitespaces)
 4689                                            .take(block_start_trimmed.len())
 4690                                            .collect::<String>();
 4691
 4692                                        if line_content.starts_with(block_start_trimmed) {
 4693                                            return None;
 4694                                        }
 4695                                    }
 4696                                }
 4697
 4698                                let cursor_is_placed_after_comment_marker =
 4699                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 4700                                if cursor_is_placed_after_comment_marker {
 4701                                    Some(delimiter.clone())
 4702                                } else {
 4703                                    None
 4704                                }
 4705                            });
 4706
 4707                            let mut indent_on_newline = IndentSize::spaces(0);
 4708                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 4709
 4710                            let doc_delimiter = maybe!({
 4711                                if !selection_is_empty {
 4712                                    return None;
 4713                                }
 4714
 4715                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4716                                    return None;
 4717                                }
 4718
 4719                                let BlockCommentConfig {
 4720                                    start: start_tag,
 4721                                    end: end_tag,
 4722                                    prefix: delimiter,
 4723                                    tab_size: len,
 4724                                } = language.documentation_comment()?;
 4725                                let is_within_block_comment = buffer
 4726                                    .language_scope_at(start_point)
 4727                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4728                                if !is_within_block_comment {
 4729                                    return None;
 4730                                }
 4731
 4732                                let (snapshot, range) =
 4733                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4734
 4735                                let num_of_whitespaces = snapshot
 4736                                    .chars_for_range(range.clone())
 4737                                    .take_while(|c| c.is_whitespace())
 4738                                    .count();
 4739
 4740                                // It is safe to use a column from MultiBufferPoint in context of a single buffer ranges, because we're only ever looking at a single line at a time.
 4741                                let column = start_point.column;
 4742                                let cursor_is_after_start_tag = {
 4743                                    let start_tag_len = start_tag.len();
 4744                                    let start_tag_line = snapshot
 4745                                        .chars_for_range(range.clone())
 4746                                        .skip(num_of_whitespaces)
 4747                                        .take(start_tag_len)
 4748                                        .collect::<String>();
 4749                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4750                                        num_of_whitespaces + start_tag_len <= column as usize
 4751                                    } else {
 4752                                        false
 4753                                    }
 4754                                };
 4755
 4756                                let cursor_is_after_delimiter = {
 4757                                    let delimiter_trim = delimiter.trim_end();
 4758                                    let delimiter_line = snapshot
 4759                                        .chars_for_range(range.clone())
 4760                                        .skip(num_of_whitespaces)
 4761                                        .take(delimiter_trim.len())
 4762                                        .collect::<String>();
 4763                                    if delimiter_line.starts_with(delimiter_trim) {
 4764                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4765                                    } else {
 4766                                        false
 4767                                    }
 4768                                };
 4769
 4770                                let cursor_is_before_end_tag_if_exists = {
 4771                                    let mut char_position = 0u32;
 4772                                    let mut end_tag_offset = None;
 4773
 4774                                    'outer: for chunk in snapshot.text_for_range(range) {
 4775                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4776                                            let chars_before_match =
 4777                                                chunk[..byte_pos].chars().count() as u32;
 4778                                            end_tag_offset =
 4779                                                Some(char_position + chars_before_match);
 4780                                            break 'outer;
 4781                                        }
 4782                                        char_position += chunk.chars().count() as u32;
 4783                                    }
 4784
 4785                                    if let Some(end_tag_offset) = end_tag_offset {
 4786                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4787                                        if cursor_is_after_start_tag {
 4788                                            if cursor_is_before_end_tag {
 4789                                                insert_extra_newline = true;
 4790                                            }
 4791                                            let cursor_is_at_start_of_end_tag =
 4792                                                column == end_tag_offset;
 4793                                            if cursor_is_at_start_of_end_tag {
 4794                                                indent_on_extra_newline.len = *len;
 4795                                            }
 4796                                        }
 4797                                        cursor_is_before_end_tag
 4798                                    } else {
 4799                                        true
 4800                                    }
 4801                                };
 4802
 4803                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4804                                    && cursor_is_before_end_tag_if_exists
 4805                                {
 4806                                    if cursor_is_after_start_tag {
 4807                                        indent_on_newline.len = *len;
 4808                                    }
 4809                                    Some(delimiter.clone())
 4810                                } else {
 4811                                    None
 4812                                }
 4813                            });
 4814
 4815                            (
 4816                                comment_delimiter,
 4817                                doc_delimiter,
 4818                                insert_extra_newline,
 4819                                indent_on_newline,
 4820                                indent_on_extra_newline,
 4821                            )
 4822                        } else {
 4823                            (
 4824                                None,
 4825                                None,
 4826                                false,
 4827                                IndentSize::default(),
 4828                                IndentSize::default(),
 4829                            )
 4830                        };
 4831
 4832                        let prevent_auto_indent = doc_delimiter.is_some();
 4833                        let delimiter = comment_delimiter.or(doc_delimiter);
 4834
 4835                        let capacity_for_delimiter =
 4836                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4837                        let mut new_text = String::with_capacity(
 4838                            1 + capacity_for_delimiter
 4839                                + existing_indent.len as usize
 4840                                + indent_on_newline.len as usize
 4841                                + indent_on_extra_newline.len as usize,
 4842                        );
 4843                        new_text.push('\n');
 4844                        new_text.extend(existing_indent.chars());
 4845                        new_text.extend(indent_on_newline.chars());
 4846
 4847                        if let Some(delimiter) = &delimiter {
 4848                            new_text.push_str(delimiter);
 4849                        }
 4850
 4851                        if insert_extra_newline {
 4852                            new_text.push('\n');
 4853                            new_text.extend(existing_indent.chars());
 4854                            new_text.extend(indent_on_extra_newline.chars());
 4855                        }
 4856
 4857                        let anchor = buffer.anchor_after(end);
 4858                        let new_selection = selection.map(|_| anchor);
 4859                        (
 4860                            ((start..end, new_text), prevent_auto_indent),
 4861                            (insert_extra_newline, new_selection),
 4862                        )
 4863                    })
 4864                    .unzip()
 4865            };
 4866
 4867            let mut auto_indent_edits = Vec::new();
 4868            let mut edits = Vec::new();
 4869            for (edit, prevent_auto_indent) in edits_with_flags {
 4870                if prevent_auto_indent {
 4871                    edits.push(edit);
 4872                } else {
 4873                    auto_indent_edits.push(edit);
 4874                }
 4875            }
 4876            if !edits.is_empty() {
 4877                this.edit(edits, cx);
 4878            }
 4879            if !auto_indent_edits.is_empty() {
 4880                this.edit_with_autoindent(auto_indent_edits, cx);
 4881            }
 4882
 4883            let buffer = this.buffer.read(cx).snapshot(cx);
 4884            let new_selections = selection_info
 4885                .into_iter()
 4886                .map(|(extra_newline_inserted, new_selection)| {
 4887                    let mut cursor = new_selection.end.to_point(&buffer);
 4888                    if extra_newline_inserted {
 4889                        cursor.row -= 1;
 4890                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4891                    }
 4892                    new_selection.map(|_| cursor)
 4893                })
 4894                .collect();
 4895
 4896            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
 4897            this.refresh_edit_prediction(true, false, window, cx);
 4898        });
 4899    }
 4900
 4901    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4902        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4903
 4904        let buffer = self.buffer.read(cx);
 4905        let snapshot = buffer.snapshot(cx);
 4906
 4907        let mut edits = Vec::new();
 4908        let mut rows = Vec::new();
 4909
 4910        for (rows_inserted, selection) in self
 4911            .selections
 4912            .all_adjusted(&self.display_snapshot(cx))
 4913            .into_iter()
 4914            .enumerate()
 4915        {
 4916            let cursor = selection.head();
 4917            let row = cursor.row;
 4918
 4919            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4920
 4921            let newline = "\n".to_string();
 4922            edits.push((start_of_line..start_of_line, newline));
 4923
 4924            rows.push(row + rows_inserted as u32);
 4925        }
 4926
 4927        self.transact(window, cx, |editor, window, cx| {
 4928            editor.edit(edits, cx);
 4929
 4930            editor.change_selections(Default::default(), window, cx, |s| {
 4931                let mut index = 0;
 4932                s.move_cursors_with(|map, _, _| {
 4933                    let row = rows[index];
 4934                    index += 1;
 4935
 4936                    let point = Point::new(row, 0);
 4937                    let boundary = map.next_line_boundary(point).1;
 4938                    let clipped = map.clip_point(boundary, Bias::Left);
 4939
 4940                    (clipped, SelectionGoal::None)
 4941                });
 4942            });
 4943
 4944            let mut indent_edits = Vec::new();
 4945            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4946            for row in rows {
 4947                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4948                for (row, indent) in indents {
 4949                    if indent.len == 0 {
 4950                        continue;
 4951                    }
 4952
 4953                    let text = match indent.kind {
 4954                        IndentKind::Space => " ".repeat(indent.len as usize),
 4955                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4956                    };
 4957                    let point = Point::new(row.0, 0);
 4958                    indent_edits.push((point..point, text));
 4959                }
 4960            }
 4961            editor.edit(indent_edits, cx);
 4962        });
 4963    }
 4964
 4965    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 4966        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4967
 4968        let buffer = self.buffer.read(cx);
 4969        let snapshot = buffer.snapshot(cx);
 4970
 4971        let mut edits = Vec::new();
 4972        let mut rows = Vec::new();
 4973        let mut rows_inserted = 0;
 4974
 4975        for selection in self.selections.all_adjusted(&self.display_snapshot(cx)) {
 4976            let cursor = selection.head();
 4977            let row = cursor.row;
 4978
 4979            let point = Point::new(row + 1, 0);
 4980            let start_of_line = snapshot.clip_point(point, Bias::Left);
 4981
 4982            let newline = "\n".to_string();
 4983            edits.push((start_of_line..start_of_line, newline));
 4984
 4985            rows_inserted += 1;
 4986            rows.push(row + rows_inserted);
 4987        }
 4988
 4989        self.transact(window, cx, |editor, window, cx| {
 4990            editor.edit(edits, cx);
 4991
 4992            editor.change_selections(Default::default(), window, cx, |s| {
 4993                let mut index = 0;
 4994                s.move_cursors_with(|map, _, _| {
 4995                    let row = rows[index];
 4996                    index += 1;
 4997
 4998                    let point = Point::new(row, 0);
 4999                    let boundary = map.next_line_boundary(point).1;
 5000                    let clipped = map.clip_point(boundary, Bias::Left);
 5001
 5002                    (clipped, SelectionGoal::None)
 5003                });
 5004            });
 5005
 5006            let mut indent_edits = Vec::new();
 5007            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 5008            for row in rows {
 5009                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 5010                for (row, indent) in indents {
 5011                    if indent.len == 0 {
 5012                        continue;
 5013                    }
 5014
 5015                    let text = match indent.kind {
 5016                        IndentKind::Space => " ".repeat(indent.len as usize),
 5017                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 5018                    };
 5019                    let point = Point::new(row.0, 0);
 5020                    indent_edits.push((point..point, text));
 5021                }
 5022            }
 5023            editor.edit(indent_edits, cx);
 5024        });
 5025    }
 5026
 5027    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 5028        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 5029            original_indent_columns: Vec::new(),
 5030        });
 5031        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 5032    }
 5033
 5034    fn insert_with_autoindent_mode(
 5035        &mut self,
 5036        text: &str,
 5037        autoindent_mode: Option<AutoindentMode>,
 5038        window: &mut Window,
 5039        cx: &mut Context<Self>,
 5040    ) {
 5041        if self.read_only(cx) {
 5042            return;
 5043        }
 5044
 5045        let text: Arc<str> = text.into();
 5046        self.transact(window, cx, |this, window, cx| {
 5047            let old_selections = this.selections.all_adjusted(&this.display_snapshot(cx));
 5048            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 5049                let anchors = {
 5050                    let snapshot = buffer.read(cx);
 5051                    old_selections
 5052                        .iter()
 5053                        .map(|s| {
 5054                            let anchor = snapshot.anchor_after(s.head());
 5055                            s.map(|_| anchor)
 5056                        })
 5057                        .collect::<Vec<_>>()
 5058                };
 5059                buffer.edit(
 5060                    old_selections
 5061                        .iter()
 5062                        .map(|s| (s.start..s.end, text.clone())),
 5063                    autoindent_mode,
 5064                    cx,
 5065                );
 5066                anchors
 5067            });
 5068
 5069            this.change_selections(Default::default(), window, cx, |s| {
 5070                s.select_anchors(selection_anchors);
 5071            });
 5072
 5073            cx.notify();
 5074        });
 5075    }
 5076
 5077    fn trigger_completion_on_input(
 5078        &mut self,
 5079        text: &str,
 5080        trigger_in_words: bool,
 5081        window: &mut Window,
 5082        cx: &mut Context<Self>,
 5083    ) {
 5084        let completions_source = self
 5085            .context_menu
 5086            .borrow()
 5087            .as_ref()
 5088            .and_then(|menu| match menu {
 5089                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 5090                CodeContextMenu::CodeActions(_) => None,
 5091            });
 5092
 5093        match completions_source {
 5094            Some(CompletionsMenuSource::Words { .. }) => {
 5095                self.open_or_update_completions_menu(
 5096                    Some(CompletionsMenuSource::Words {
 5097                        ignore_threshold: false,
 5098                    }),
 5099                    None,
 5100                    window,
 5101                    cx,
 5102                );
 5103            }
 5104            Some(CompletionsMenuSource::Normal)
 5105            | Some(CompletionsMenuSource::SnippetChoices)
 5106            | None
 5107                if self.is_completion_trigger(
 5108                    text,
 5109                    trigger_in_words,
 5110                    completions_source.is_some(),
 5111                    cx,
 5112                ) =>
 5113            {
 5114                self.show_completions(
 5115                    &ShowCompletions {
 5116                        trigger: Some(text.to_owned()).filter(|x| !x.is_empty()),
 5117                    },
 5118                    window,
 5119                    cx,
 5120                )
 5121            }
 5122            _ => {
 5123                self.hide_context_menu(window, cx);
 5124            }
 5125        }
 5126    }
 5127
 5128    fn is_completion_trigger(
 5129        &self,
 5130        text: &str,
 5131        trigger_in_words: bool,
 5132        menu_is_open: bool,
 5133        cx: &mut Context<Self>,
 5134    ) -> bool {
 5135        let position = self.selections.newest_anchor().head();
 5136        let Some(buffer) = self.buffer.read(cx).buffer_for_anchor(position, cx) else {
 5137            return false;
 5138        };
 5139
 5140        if let Some(completion_provider) = &self.completion_provider {
 5141            completion_provider.is_completion_trigger(
 5142                &buffer,
 5143                position.text_anchor,
 5144                text,
 5145                trigger_in_words,
 5146                menu_is_open,
 5147                cx,
 5148            )
 5149        } else {
 5150            false
 5151        }
 5152    }
 5153
 5154    /// If any empty selections is touching the start of its innermost containing autoclose
 5155    /// region, expand it to select the brackets.
 5156    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 5157        let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
 5158        let buffer = self.buffer.read(cx).read(cx);
 5159        let new_selections = self
 5160            .selections_with_autoclose_regions(selections, &buffer)
 5161            .map(|(mut selection, region)| {
 5162                if !selection.is_empty() {
 5163                    return selection;
 5164                }
 5165
 5166                if let Some(region) = region {
 5167                    let mut range = region.range.to_offset(&buffer);
 5168                    if selection.start == range.start && range.start >= region.pair.start.len() {
 5169                        range.start -= region.pair.start.len();
 5170                        if buffer.contains_str_at(range.start, &region.pair.start)
 5171                            && buffer.contains_str_at(range.end, &region.pair.end)
 5172                        {
 5173                            range.end += region.pair.end.len();
 5174                            selection.start = range.start;
 5175                            selection.end = range.end;
 5176
 5177                            return selection;
 5178                        }
 5179                    }
 5180                }
 5181
 5182                let always_treat_brackets_as_autoclosed = buffer
 5183                    .language_settings_at(selection.start, cx)
 5184                    .always_treat_brackets_as_autoclosed;
 5185
 5186                if !always_treat_brackets_as_autoclosed {
 5187                    return selection;
 5188                }
 5189
 5190                if let Some(scope) = buffer.language_scope_at(selection.start) {
 5191                    for (pair, enabled) in scope.brackets() {
 5192                        if !enabled || !pair.close {
 5193                            continue;
 5194                        }
 5195
 5196                        if buffer.contains_str_at(selection.start, &pair.end) {
 5197                            let pair_start_len = pair.start.len();
 5198                            if buffer.contains_str_at(
 5199                                selection.start.saturating_sub(pair_start_len),
 5200                                &pair.start,
 5201                            ) {
 5202                                selection.start -= pair_start_len;
 5203                                selection.end += pair.end.len();
 5204
 5205                                return selection;
 5206                            }
 5207                        }
 5208                    }
 5209                }
 5210
 5211                selection
 5212            })
 5213            .collect();
 5214
 5215        drop(buffer);
 5216        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
 5217            selections.select(new_selections)
 5218        });
 5219    }
 5220
 5221    /// Iterate the given selections, and for each one, find the smallest surrounding
 5222    /// autoclose region. This uses the ordering of the selections and the autoclose
 5223    /// regions to avoid repeated comparisons.
 5224    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 5225        &'a self,
 5226        selections: impl IntoIterator<Item = Selection<D>>,
 5227        buffer: &'a MultiBufferSnapshot,
 5228    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 5229        let mut i = 0;
 5230        let mut regions = self.autoclose_regions.as_slice();
 5231        selections.into_iter().map(move |selection| {
 5232            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 5233
 5234            let mut enclosing = None;
 5235            while let Some(pair_state) = regions.get(i) {
 5236                if pair_state.range.end.to_offset(buffer) < range.start {
 5237                    regions = &regions[i + 1..];
 5238                    i = 0;
 5239                } else if pair_state.range.start.to_offset(buffer) > range.end {
 5240                    break;
 5241                } else {
 5242                    if pair_state.selection_id == selection.id {
 5243                        enclosing = Some(pair_state);
 5244                    }
 5245                    i += 1;
 5246                }
 5247            }
 5248
 5249            (selection, enclosing)
 5250        })
 5251    }
 5252
 5253    /// Remove any autoclose regions that no longer contain their selection or have invalid anchors in ranges.
 5254    fn invalidate_autoclose_regions(
 5255        &mut self,
 5256        mut selections: &[Selection<Anchor>],
 5257        buffer: &MultiBufferSnapshot,
 5258    ) {
 5259        self.autoclose_regions.retain(|state| {
 5260            if !state.range.start.is_valid(buffer) || !state.range.end.is_valid(buffer) {
 5261                return false;
 5262            }
 5263
 5264            let mut i = 0;
 5265            while let Some(selection) = selections.get(i) {
 5266                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 5267                    selections = &selections[1..];
 5268                    continue;
 5269                }
 5270                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 5271                    break;
 5272                }
 5273                if selection.id == state.selection_id {
 5274                    return true;
 5275                } else {
 5276                    i += 1;
 5277                }
 5278            }
 5279            false
 5280        });
 5281    }
 5282
 5283    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 5284        let offset = position.to_offset(buffer);
 5285        let (word_range, kind) =
 5286            buffer.surrounding_word(offset, Some(CharScopeContext::Completion));
 5287        if offset > word_range.start && kind == Some(CharKind::Word) {
 5288            Some(
 5289                buffer
 5290                    .text_for_range(word_range.start..offset)
 5291                    .collect::<String>(),
 5292            )
 5293        } else {
 5294            None
 5295        }
 5296    }
 5297
 5298    pub fn visible_excerpts(
 5299        &self,
 5300        cx: &mut Context<Editor>,
 5301    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 5302        let Some(project) = self.project() else {
 5303            return HashMap::default();
 5304        };
 5305        let project = project.read(cx);
 5306        let multi_buffer = self.buffer().read(cx);
 5307        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 5308        let multi_buffer_visible_start = self
 5309            .scroll_manager
 5310            .anchor()
 5311            .anchor
 5312            .to_point(&multi_buffer_snapshot);
 5313        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 5314            multi_buffer_visible_start
 5315                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 5316            Bias::Left,
 5317        );
 5318        multi_buffer_snapshot
 5319            .range_to_buffer_ranges(multi_buffer_visible_start..multi_buffer_visible_end)
 5320            .into_iter()
 5321            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 5322            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 5323                let buffer_file = project::File::from_dyn(buffer.file())?;
 5324                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 5325                let worktree_entry = buffer_worktree
 5326                    .read(cx)
 5327                    .entry_for_id(buffer_file.project_entry_id()?)?;
 5328                if worktree_entry.is_ignored {
 5329                    None
 5330                } else {
 5331                    Some((
 5332                        excerpt_id,
 5333                        (
 5334                            multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5335                            buffer.version().clone(),
 5336                            excerpt_visible_range,
 5337                        ),
 5338                    ))
 5339                }
 5340            })
 5341            .collect()
 5342    }
 5343
 5344    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 5345        TextLayoutDetails {
 5346            text_system: window.text_system().clone(),
 5347            editor_style: self.style.clone().unwrap(),
 5348            rem_size: window.rem_size(),
 5349            scroll_anchor: self.scroll_manager.anchor(),
 5350            visible_rows: self.visible_line_count(),
 5351            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 5352        }
 5353    }
 5354
 5355    fn trigger_on_type_formatting(
 5356        &self,
 5357        input: String,
 5358        window: &mut Window,
 5359        cx: &mut Context<Self>,
 5360    ) -> Option<Task<Result<()>>> {
 5361        if input.len() != 1 {
 5362            return None;
 5363        }
 5364
 5365        let project = self.project()?;
 5366        let position = self.selections.newest_anchor().head();
 5367        let (buffer, buffer_position) = self
 5368            .buffer
 5369            .read(cx)
 5370            .text_anchor_for_position(position, cx)?;
 5371
 5372        let settings = language_settings::language_settings(
 5373            buffer
 5374                .read(cx)
 5375                .language_at(buffer_position)
 5376                .map(|l| l.name()),
 5377            buffer.read(cx).file(),
 5378            cx,
 5379        );
 5380        if !settings.use_on_type_format {
 5381            return None;
 5382        }
 5383
 5384        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5385        // hence we do LSP request & edit on host side only — add formats to host's history.
 5386        let push_to_lsp_host_history = true;
 5387        // If this is not the host, append its history with new edits.
 5388        let push_to_client_history = project.read(cx).is_via_collab();
 5389
 5390        let on_type_formatting = project.update(cx, |project, cx| {
 5391            project.on_type_format(
 5392                buffer.clone(),
 5393                buffer_position,
 5394                input,
 5395                push_to_lsp_host_history,
 5396                cx,
 5397            )
 5398        });
 5399        Some(cx.spawn_in(window, async move |editor, cx| {
 5400            if let Some(transaction) = on_type_formatting.await? {
 5401                if push_to_client_history {
 5402                    buffer
 5403                        .update(cx, |buffer, _| {
 5404                            buffer.push_transaction(transaction, Instant::now());
 5405                            buffer.finalize_last_transaction();
 5406                        })
 5407                        .ok();
 5408                }
 5409                editor.update(cx, |editor, cx| {
 5410                    editor.refresh_document_highlights(cx);
 5411                })?;
 5412            }
 5413            Ok(())
 5414        }))
 5415    }
 5416
 5417    pub fn show_word_completions(
 5418        &mut self,
 5419        _: &ShowWordCompletions,
 5420        window: &mut Window,
 5421        cx: &mut Context<Self>,
 5422    ) {
 5423        self.open_or_update_completions_menu(
 5424            Some(CompletionsMenuSource::Words {
 5425                ignore_threshold: true,
 5426            }),
 5427            None,
 5428            window,
 5429            cx,
 5430        );
 5431    }
 5432
 5433    pub fn show_completions(
 5434        &mut self,
 5435        options: &ShowCompletions,
 5436        window: &mut Window,
 5437        cx: &mut Context<Self>,
 5438    ) {
 5439        self.open_or_update_completions_menu(None, options.trigger.as_deref(), window, cx);
 5440    }
 5441
 5442    fn open_or_update_completions_menu(
 5443        &mut self,
 5444        requested_source: Option<CompletionsMenuSource>,
 5445        trigger: Option<&str>,
 5446        window: &mut Window,
 5447        cx: &mut Context<Self>,
 5448    ) {
 5449        if self.pending_rename.is_some() {
 5450            return;
 5451        }
 5452
 5453        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5454
 5455        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5456        // inserted and selected. To handle that case, the start of the selection is used so that
 5457        // the menu starts with all choices.
 5458        let position = self
 5459            .selections
 5460            .newest_anchor()
 5461            .start
 5462            .bias_right(&multibuffer_snapshot);
 5463        if position.diff_base_anchor.is_some() {
 5464            return;
 5465        }
 5466        let buffer_position = multibuffer_snapshot.anchor_before(position);
 5467        let Some(buffer) = buffer_position
 5468            .buffer_id
 5469            .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
 5470        else {
 5471            return;
 5472        };
 5473        let buffer_snapshot = buffer.read(cx).snapshot();
 5474
 5475        let query: Option<Arc<String>> =
 5476            Self::completion_query(&multibuffer_snapshot, buffer_position)
 5477                .map(|query| query.into());
 5478
 5479        drop(multibuffer_snapshot);
 5480
 5481        // Hide the current completions menu when query is empty. Without this, cached
 5482        // completions from before the trigger char may be reused (#32774).
 5483        if query.is_none() {
 5484            let menu_is_open = matches!(
 5485                self.context_menu.borrow().as_ref(),
 5486                Some(CodeContextMenu::Completions(_))
 5487            );
 5488            if menu_is_open {
 5489                self.hide_context_menu(window, cx);
 5490            }
 5491        }
 5492
 5493        let mut ignore_word_threshold = false;
 5494        let provider = match requested_source {
 5495            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5496            Some(CompletionsMenuSource::Words { ignore_threshold }) => {
 5497                ignore_word_threshold = ignore_threshold;
 5498                None
 5499            }
 5500            Some(CompletionsMenuSource::SnippetChoices) => {
 5501                log::error!("bug: SnippetChoices requested_source is not handled");
 5502                None
 5503            }
 5504        };
 5505
 5506        let sort_completions = provider
 5507            .as_ref()
 5508            .is_some_and(|provider| provider.sort_completions());
 5509
 5510        let filter_completions = provider
 5511            .as_ref()
 5512            .is_none_or(|provider| provider.filter_completions());
 5513
 5514        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5515            if filter_completions {
 5516                menu.filter(query.clone(), provider.clone(), window, cx);
 5517            }
 5518            // When `is_incomplete` is false, no need to re-query completions when the current query
 5519            // is a suffix of the initial query.
 5520            if !menu.is_incomplete {
 5521                // If the new query is a suffix of the old query (typing more characters) and
 5522                // the previous result was complete, the existing completions can be filtered.
 5523                //
 5524                // Note that this is always true for snippet completions.
 5525                let query_matches = match (&menu.initial_query, &query) {
 5526                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5527                    (None, _) => true,
 5528                    _ => false,
 5529                };
 5530                if query_matches {
 5531                    let position_matches = if menu.initial_position == position {
 5532                        true
 5533                    } else {
 5534                        let snapshot = self.buffer.read(cx).read(cx);
 5535                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5536                    };
 5537                    if position_matches {
 5538                        return;
 5539                    }
 5540                }
 5541            }
 5542        };
 5543
 5544        let trigger_kind = match trigger {
 5545            Some(trigger) if buffer.read(cx).completion_triggers().contains(trigger) => {
 5546                CompletionTriggerKind::TRIGGER_CHARACTER
 5547            }
 5548            _ => CompletionTriggerKind::INVOKED,
 5549        };
 5550        let completion_context = CompletionContext {
 5551            trigger_character: trigger.and_then(|trigger| {
 5552                if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER {
 5553                    Some(String::from(trigger))
 5554                } else {
 5555                    None
 5556                }
 5557            }),
 5558            trigger_kind,
 5559        };
 5560
 5561        let Anchor {
 5562            excerpt_id: buffer_excerpt_id,
 5563            text_anchor: buffer_position,
 5564            ..
 5565        } = buffer_position;
 5566
 5567        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5568            buffer_snapshot.surrounding_word(buffer_position, None)
 5569        {
 5570            let word_to_exclude = buffer_snapshot
 5571                .text_for_range(word_range.clone())
 5572                .collect::<String>();
 5573            (
 5574                buffer_snapshot.anchor_before(word_range.start)
 5575                    ..buffer_snapshot.anchor_after(buffer_position),
 5576                Some(word_to_exclude),
 5577            )
 5578        } else {
 5579            (buffer_position..buffer_position, None)
 5580        };
 5581
 5582        let language = buffer_snapshot
 5583            .language_at(buffer_position)
 5584            .map(|language| language.name());
 5585
 5586        let completion_settings = language_settings(language.clone(), buffer_snapshot.file(), cx)
 5587            .completions
 5588            .clone();
 5589
 5590        let show_completion_documentation = buffer_snapshot
 5591            .settings_at(buffer_position, cx)
 5592            .show_completion_documentation;
 5593
 5594        // The document can be large, so stay in reasonable bounds when searching for words,
 5595        // otherwise completion pop-up might be slow to appear.
 5596        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5597        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5598        let min_word_search = buffer_snapshot.clip_point(
 5599            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5600            Bias::Left,
 5601        );
 5602        let max_word_search = buffer_snapshot.clip_point(
 5603            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5604            Bias::Right,
 5605        );
 5606        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5607            ..buffer_snapshot.point_to_offset(max_word_search);
 5608
 5609        let skip_digits = query
 5610            .as_ref()
 5611            .is_none_or(|query| !query.chars().any(|c| c.is_digit(10)));
 5612
 5613        let omit_word_completions = !self.word_completions_enabled
 5614            || (!ignore_word_threshold
 5615                && match &query {
 5616                    Some(query) => query.chars().count() < completion_settings.words_min_length,
 5617                    None => completion_settings.words_min_length != 0,
 5618                });
 5619
 5620        let (mut words, provider_responses) = match &provider {
 5621            Some(provider) => {
 5622                let provider_responses = provider.completions(
 5623                    buffer_excerpt_id,
 5624                    &buffer,
 5625                    buffer_position,
 5626                    completion_context,
 5627                    window,
 5628                    cx,
 5629                );
 5630
 5631                let words = match (omit_word_completions, completion_settings.words) {
 5632                    (true, _) | (_, WordsCompletionMode::Disabled) => {
 5633                        Task::ready(BTreeMap::default())
 5634                    }
 5635                    (false, WordsCompletionMode::Enabled | WordsCompletionMode::Fallback) => cx
 5636                        .background_spawn(async move {
 5637                            buffer_snapshot.words_in_range(WordsQuery {
 5638                                fuzzy_contents: None,
 5639                                range: word_search_range,
 5640                                skip_digits,
 5641                            })
 5642                        }),
 5643                };
 5644
 5645                (words, provider_responses)
 5646            }
 5647            None => {
 5648                let words = if omit_word_completions {
 5649                    Task::ready(BTreeMap::default())
 5650                } else {
 5651                    cx.background_spawn(async move {
 5652                        buffer_snapshot.words_in_range(WordsQuery {
 5653                            fuzzy_contents: None,
 5654                            range: word_search_range,
 5655                            skip_digits,
 5656                        })
 5657                    })
 5658                };
 5659                (words, Task::ready(Ok(Vec::new())))
 5660            }
 5661        };
 5662
 5663        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5664
 5665        let id = post_inc(&mut self.next_completion_id);
 5666        let task = cx.spawn_in(window, async move |editor, cx| {
 5667            let Ok(()) = editor.update(cx, |this, _| {
 5668                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5669            }) else {
 5670                return;
 5671            };
 5672
 5673            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5674            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5675            let mut completions = Vec::new();
 5676            let mut is_incomplete = false;
 5677            let mut display_options: Option<CompletionDisplayOptions> = None;
 5678            if let Some(provider_responses) = provider_responses.await.log_err()
 5679                && !provider_responses.is_empty()
 5680            {
 5681                for response in provider_responses {
 5682                    completions.extend(response.completions);
 5683                    is_incomplete = is_incomplete || response.is_incomplete;
 5684                    match display_options.as_mut() {
 5685                        None => {
 5686                            display_options = Some(response.display_options);
 5687                        }
 5688                        Some(options) => options.merge(&response.display_options),
 5689                    }
 5690                }
 5691                if completion_settings.words == WordsCompletionMode::Fallback {
 5692                    words = Task::ready(BTreeMap::default());
 5693                }
 5694            }
 5695            let display_options = display_options.unwrap_or_default();
 5696
 5697            let mut words = words.await;
 5698            if let Some(word_to_exclude) = &word_to_exclude {
 5699                words.remove(word_to_exclude);
 5700            }
 5701            for lsp_completion in &completions {
 5702                words.remove(&lsp_completion.new_text);
 5703            }
 5704            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5705                replace_range: word_replace_range.clone(),
 5706                new_text: word.clone(),
 5707                label: CodeLabel::plain(word, None),
 5708                icon_path: None,
 5709                documentation: None,
 5710                source: CompletionSource::BufferWord {
 5711                    word_range,
 5712                    resolved: false,
 5713                },
 5714                insert_text_mode: Some(InsertTextMode::AS_IS),
 5715                confirm: None,
 5716            }));
 5717
 5718            let menu = if completions.is_empty() {
 5719                None
 5720            } else {
 5721                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5722                    let languages = editor
 5723                        .workspace
 5724                        .as_ref()
 5725                        .and_then(|(workspace, _)| workspace.upgrade())
 5726                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5727                    let menu = CompletionsMenu::new(
 5728                        id,
 5729                        requested_source.unwrap_or(CompletionsMenuSource::Normal),
 5730                        sort_completions,
 5731                        show_completion_documentation,
 5732                        position,
 5733                        query.clone(),
 5734                        is_incomplete,
 5735                        buffer.clone(),
 5736                        completions.into(),
 5737                        display_options,
 5738                        snippet_sort_order,
 5739                        languages,
 5740                        language,
 5741                        cx,
 5742                    );
 5743
 5744                    let query = if filter_completions { query } else { None };
 5745                    let matches_task = if let Some(query) = query {
 5746                        menu.do_async_filtering(query, cx)
 5747                    } else {
 5748                        Task::ready(menu.unfiltered_matches())
 5749                    };
 5750                    (menu, matches_task)
 5751                }) else {
 5752                    return;
 5753                };
 5754
 5755                let matches = matches_task.await;
 5756
 5757                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5758                    // Newer menu already set, so exit.
 5759                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5760                        editor.context_menu.borrow().as_ref()
 5761                        && prev_menu.id > id
 5762                    {
 5763                        return;
 5764                    };
 5765
 5766                    // Only valid to take prev_menu because it the new menu is immediately set
 5767                    // below, or the menu is hidden.
 5768                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5769                        editor.context_menu.borrow_mut().take()
 5770                    {
 5771                        let position_matches =
 5772                            if prev_menu.initial_position == menu.initial_position {
 5773                                true
 5774                            } else {
 5775                                let snapshot = editor.buffer.read(cx).read(cx);
 5776                                prev_menu.initial_position.to_offset(&snapshot)
 5777                                    == menu.initial_position.to_offset(&snapshot)
 5778                            };
 5779                        if position_matches {
 5780                            // Preserve markdown cache before `set_filter_results` because it will
 5781                            // try to populate the documentation cache.
 5782                            menu.preserve_markdown_cache(prev_menu);
 5783                        }
 5784                    };
 5785
 5786                    menu.set_filter_results(matches, provider, window, cx);
 5787                }) else {
 5788                    return;
 5789                };
 5790
 5791                menu.visible().then_some(menu)
 5792            };
 5793
 5794            editor
 5795                .update_in(cx, |editor, window, cx| {
 5796                    if editor.focus_handle.is_focused(window)
 5797                        && let Some(menu) = menu
 5798                    {
 5799                        *editor.context_menu.borrow_mut() =
 5800                            Some(CodeContextMenu::Completions(menu));
 5801
 5802                        crate::hover_popover::hide_hover(editor, cx);
 5803                        if editor.show_edit_predictions_in_menu() {
 5804                            editor.update_visible_edit_prediction(window, cx);
 5805                        } else {
 5806                            editor.discard_edit_prediction(false, cx);
 5807                        }
 5808
 5809                        cx.notify();
 5810                        return;
 5811                    }
 5812
 5813                    if editor.completion_tasks.len() <= 1 {
 5814                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 5815                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5816                        // If it was already hidden and we don't show edit predictions in the menu,
 5817                        // we should also show the edit prediction when available.
 5818                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5819                            editor.update_visible_edit_prediction(window, cx);
 5820                        }
 5821                    }
 5822                })
 5823                .ok();
 5824        });
 5825
 5826        self.completion_tasks.push((id, task));
 5827    }
 5828
 5829    #[cfg(feature = "test-support")]
 5830    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5831        let menu = self.context_menu.borrow();
 5832        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5833            let completions = menu.completions.borrow();
 5834            Some(completions.to_vec())
 5835        } else {
 5836            None
 5837        }
 5838    }
 5839
 5840    pub fn with_completions_menu_matching_id<R>(
 5841        &self,
 5842        id: CompletionId,
 5843        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 5844    ) -> R {
 5845        let mut context_menu = self.context_menu.borrow_mut();
 5846        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 5847            return f(None);
 5848        };
 5849        if completions_menu.id != id {
 5850            return f(None);
 5851        }
 5852        f(Some(completions_menu))
 5853    }
 5854
 5855    pub fn confirm_completion(
 5856        &mut self,
 5857        action: &ConfirmCompletion,
 5858        window: &mut Window,
 5859        cx: &mut Context<Self>,
 5860    ) -> Option<Task<Result<()>>> {
 5861        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5862        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5863    }
 5864
 5865    pub fn confirm_completion_insert(
 5866        &mut self,
 5867        _: &ConfirmCompletionInsert,
 5868        window: &mut Window,
 5869        cx: &mut Context<Self>,
 5870    ) -> Option<Task<Result<()>>> {
 5871        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5872        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5873    }
 5874
 5875    pub fn confirm_completion_replace(
 5876        &mut self,
 5877        _: &ConfirmCompletionReplace,
 5878        window: &mut Window,
 5879        cx: &mut Context<Self>,
 5880    ) -> Option<Task<Result<()>>> {
 5881        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5882        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5883    }
 5884
 5885    pub fn compose_completion(
 5886        &mut self,
 5887        action: &ComposeCompletion,
 5888        window: &mut Window,
 5889        cx: &mut Context<Self>,
 5890    ) -> Option<Task<Result<()>>> {
 5891        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5892        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5893    }
 5894
 5895    fn do_completion(
 5896        &mut self,
 5897        item_ix: Option<usize>,
 5898        intent: CompletionIntent,
 5899        window: &mut Window,
 5900        cx: &mut Context<Editor>,
 5901    ) -> Option<Task<Result<()>>> {
 5902        use language::ToOffset as _;
 5903
 5904        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5905        else {
 5906            return None;
 5907        };
 5908
 5909        let candidate_id = {
 5910            let entries = completions_menu.entries.borrow();
 5911            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5912            if self.show_edit_predictions_in_menu() {
 5913                self.discard_edit_prediction(true, cx);
 5914            }
 5915            mat.candidate_id
 5916        };
 5917
 5918        let completion = completions_menu
 5919            .completions
 5920            .borrow()
 5921            .get(candidate_id)?
 5922            .clone();
 5923        cx.stop_propagation();
 5924
 5925        let buffer_handle = completions_menu.buffer.clone();
 5926
 5927        let CompletionEdit {
 5928            new_text,
 5929            snippet,
 5930            replace_range,
 5931        } = process_completion_for_edit(
 5932            &completion,
 5933            intent,
 5934            &buffer_handle,
 5935            &completions_menu.initial_position.text_anchor,
 5936            cx,
 5937        );
 5938
 5939        let buffer = buffer_handle.read(cx);
 5940        let snapshot = self.buffer.read(cx).snapshot(cx);
 5941        let newest_anchor = self.selections.newest_anchor();
 5942        let replace_range_multibuffer = {
 5943            let mut excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 5944            excerpt.map_range_from_buffer(replace_range.clone())
 5945        };
 5946        if snapshot.buffer_id_for_anchor(newest_anchor.head()) != Some(buffer.remote_id()) {
 5947            return None;
 5948        }
 5949
 5950        let old_text = buffer
 5951            .text_for_range(replace_range.clone())
 5952            .collect::<String>();
 5953        let lookbehind = newest_anchor
 5954            .start
 5955            .text_anchor
 5956            .to_offset(buffer)
 5957            .saturating_sub(replace_range.start);
 5958        let lookahead = replace_range
 5959            .end
 5960            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 5961        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 5962        let suffix = &old_text[lookbehind.min(old_text.len())..];
 5963
 5964        let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
 5965        let mut ranges = Vec::new();
 5966        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 5967
 5968        for selection in &selections {
 5969            let range = if selection.id == newest_anchor.id {
 5970                replace_range_multibuffer.clone()
 5971            } else {
 5972                let mut range = selection.range();
 5973
 5974                // if prefix is present, don't duplicate it
 5975                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 5976                    range.start = range.start.saturating_sub(lookbehind);
 5977
 5978                    // if suffix is also present, mimic the newest cursor and replace it
 5979                    if selection.id != newest_anchor.id
 5980                        && snapshot.contains_str_at(range.end, suffix)
 5981                    {
 5982                        range.end += lookahead;
 5983                    }
 5984                }
 5985                range
 5986            };
 5987
 5988            ranges.push(range.clone());
 5989
 5990            if !self.linked_edit_ranges.is_empty() {
 5991                let start_anchor = snapshot.anchor_before(range.start);
 5992                let end_anchor = snapshot.anchor_after(range.end);
 5993                if let Some(ranges) = self
 5994                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 5995                {
 5996                    for (buffer, edits) in ranges {
 5997                        linked_edits
 5998                            .entry(buffer.clone())
 5999                            .or_default()
 6000                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 6001                    }
 6002                }
 6003            }
 6004        }
 6005
 6006        let common_prefix_len = old_text
 6007            .chars()
 6008            .zip(new_text.chars())
 6009            .take_while(|(a, b)| a == b)
 6010            .map(|(a, _)| a.len_utf8())
 6011            .sum::<usize>();
 6012
 6013        cx.emit(EditorEvent::InputHandled {
 6014            utf16_range_to_replace: None,
 6015            text: new_text[common_prefix_len..].into(),
 6016        });
 6017
 6018        self.transact(window, cx, |editor, window, cx| {
 6019            if let Some(mut snippet) = snippet {
 6020                snippet.text = new_text.to_string();
 6021                editor
 6022                    .insert_snippet(&ranges, snippet, window, cx)
 6023                    .log_err();
 6024            } else {
 6025                editor.buffer.update(cx, |multi_buffer, cx| {
 6026                    let auto_indent = match completion.insert_text_mode {
 6027                        Some(InsertTextMode::AS_IS) => None,
 6028                        _ => editor.autoindent_mode.clone(),
 6029                    };
 6030                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 6031                    multi_buffer.edit(edits, auto_indent, cx);
 6032                });
 6033            }
 6034            for (buffer, edits) in linked_edits {
 6035                buffer.update(cx, |buffer, cx| {
 6036                    let snapshot = buffer.snapshot();
 6037                    let edits = edits
 6038                        .into_iter()
 6039                        .map(|(range, text)| {
 6040                            use text::ToPoint as TP;
 6041                            let end_point = TP::to_point(&range.end, &snapshot);
 6042                            let start_point = TP::to_point(&range.start, &snapshot);
 6043                            (start_point..end_point, text)
 6044                        })
 6045                        .sorted_by_key(|(range, _)| range.start);
 6046                    buffer.edit(edits, None, cx);
 6047                })
 6048            }
 6049
 6050            editor.refresh_edit_prediction(true, false, window, cx);
 6051        });
 6052        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors_arc(), &snapshot);
 6053
 6054        let show_new_completions_on_confirm = completion
 6055            .confirm
 6056            .as_ref()
 6057            .is_some_and(|confirm| confirm(intent, window, cx));
 6058        if show_new_completions_on_confirm {
 6059            self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 6060        }
 6061
 6062        let provider = self.completion_provider.as_ref()?;
 6063        drop(completion);
 6064        let apply_edits = provider.apply_additional_edits_for_completion(
 6065            buffer_handle,
 6066            completions_menu.completions.clone(),
 6067            candidate_id,
 6068            true,
 6069            cx,
 6070        );
 6071
 6072        let editor_settings = EditorSettings::get_global(cx);
 6073        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 6074            // After the code completion is finished, users often want to know what signatures are needed.
 6075            // so we should automatically call signature_help
 6076            self.show_signature_help(&ShowSignatureHelp, window, cx);
 6077        }
 6078
 6079        Some(cx.foreground_executor().spawn(async move {
 6080            apply_edits.await?;
 6081            Ok(())
 6082        }))
 6083    }
 6084
 6085    pub fn toggle_code_actions(
 6086        &mut self,
 6087        action: &ToggleCodeActions,
 6088        window: &mut Window,
 6089        cx: &mut Context<Self>,
 6090    ) {
 6091        let quick_launch = action.quick_launch;
 6092        let mut context_menu = self.context_menu.borrow_mut();
 6093        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 6094            if code_actions.deployed_from == action.deployed_from {
 6095                // Toggle if we're selecting the same one
 6096                *context_menu = None;
 6097                cx.notify();
 6098                return;
 6099            } else {
 6100                // Otherwise, clear it and start a new one
 6101                *context_menu = None;
 6102                cx.notify();
 6103            }
 6104        }
 6105        drop(context_menu);
 6106        let snapshot = self.snapshot(window, cx);
 6107        let deployed_from = action.deployed_from.clone();
 6108        let action = action.clone();
 6109        self.completion_tasks.clear();
 6110        self.discard_edit_prediction(false, cx);
 6111
 6112        let multibuffer_point = match &action.deployed_from {
 6113            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 6114                DisplayPoint::new(*row, 0).to_point(&snapshot)
 6115            }
 6116            _ => self
 6117                .selections
 6118                .newest::<Point>(&snapshot.display_snapshot)
 6119                .head(),
 6120        };
 6121        let Some((buffer, buffer_row)) = snapshot
 6122            .buffer_snapshot()
 6123            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 6124            .and_then(|(buffer_snapshot, range)| {
 6125                self.buffer()
 6126                    .read(cx)
 6127                    .buffer(buffer_snapshot.remote_id())
 6128                    .map(|buffer| (buffer, range.start.row))
 6129            })
 6130        else {
 6131            return;
 6132        };
 6133        let buffer_id = buffer.read(cx).remote_id();
 6134        let tasks = self
 6135            .tasks
 6136            .get(&(buffer_id, buffer_row))
 6137            .map(|t| Arc::new(t.to_owned()));
 6138
 6139        if !self.focus_handle.is_focused(window) {
 6140            return;
 6141        }
 6142        let project = self.project.clone();
 6143
 6144        let code_actions_task = match deployed_from {
 6145            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 6146            _ => self.code_actions(buffer_row, window, cx),
 6147        };
 6148
 6149        let runnable_task = match deployed_from {
 6150            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 6151            _ => {
 6152                let mut task_context_task = Task::ready(None);
 6153                if let Some(tasks) = &tasks
 6154                    && let Some(project) = project
 6155                {
 6156                    task_context_task =
 6157                        Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx);
 6158                }
 6159
 6160                cx.spawn_in(window, {
 6161                    let buffer = buffer.clone();
 6162                    async move |editor, cx| {
 6163                        let task_context = task_context_task.await;
 6164
 6165                        let resolved_tasks =
 6166                            tasks
 6167                                .zip(task_context.clone())
 6168                                .map(|(tasks, task_context)| ResolvedTasks {
 6169                                    templates: tasks.resolve(&task_context).collect(),
 6170                                    position: snapshot.buffer_snapshot().anchor_before(Point::new(
 6171                                        multibuffer_point.row,
 6172                                        tasks.column,
 6173                                    )),
 6174                                });
 6175                        let debug_scenarios = editor
 6176                            .update(cx, |editor, cx| {
 6177                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 6178                            })?
 6179                            .await;
 6180                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 6181                    }
 6182                })
 6183            }
 6184        };
 6185
 6186        cx.spawn_in(window, async move |editor, cx| {
 6187            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 6188            let code_actions = code_actions_task.await;
 6189            let spawn_straight_away = quick_launch
 6190                && resolved_tasks
 6191                    .as_ref()
 6192                    .is_some_and(|tasks| tasks.templates.len() == 1)
 6193                && code_actions
 6194                    .as_ref()
 6195                    .is_none_or(|actions| actions.is_empty())
 6196                && debug_scenarios.is_empty();
 6197
 6198            editor.update_in(cx, |editor, window, cx| {
 6199                crate::hover_popover::hide_hover(editor, cx);
 6200                let actions = CodeActionContents::new(
 6201                    resolved_tasks,
 6202                    code_actions,
 6203                    debug_scenarios,
 6204                    task_context.unwrap_or_default(),
 6205                );
 6206
 6207                // Don't show the menu if there are no actions available
 6208                if actions.is_empty() {
 6209                    cx.notify();
 6210                    return Task::ready(Ok(()));
 6211                }
 6212
 6213                *editor.context_menu.borrow_mut() =
 6214                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 6215                        buffer,
 6216                        actions,
 6217                        selected_item: Default::default(),
 6218                        scroll_handle: UniformListScrollHandle::default(),
 6219                        deployed_from,
 6220                    }));
 6221                cx.notify();
 6222                if spawn_straight_away
 6223                    && let Some(task) = editor.confirm_code_action(
 6224                        &ConfirmCodeAction { item_ix: Some(0) },
 6225                        window,
 6226                        cx,
 6227                    )
 6228                {
 6229                    return task;
 6230                }
 6231
 6232                Task::ready(Ok(()))
 6233            })
 6234        })
 6235        .detach_and_log_err(cx);
 6236    }
 6237
 6238    fn debug_scenarios(
 6239        &mut self,
 6240        resolved_tasks: &Option<ResolvedTasks>,
 6241        buffer: &Entity<Buffer>,
 6242        cx: &mut App,
 6243    ) -> Task<Vec<task::DebugScenario>> {
 6244        maybe!({
 6245            let project = self.project()?;
 6246            let dap_store = project.read(cx).dap_store();
 6247            let mut scenarios = vec![];
 6248            let resolved_tasks = resolved_tasks.as_ref()?;
 6249            let buffer = buffer.read(cx);
 6250            let language = buffer.language()?;
 6251            let file = buffer.file();
 6252            let debug_adapter = language_settings(language.name().into(), file, cx)
 6253                .debuggers
 6254                .first()
 6255                .map(SharedString::from)
 6256                .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 6257
 6258            dap_store.update(cx, |dap_store, cx| {
 6259                for (_, task) in &resolved_tasks.templates {
 6260                    let maybe_scenario = dap_store.debug_scenario_for_build_task(
 6261                        task.original_task().clone(),
 6262                        debug_adapter.clone().into(),
 6263                        task.display_label().to_owned().into(),
 6264                        cx,
 6265                    );
 6266                    scenarios.push(maybe_scenario);
 6267                }
 6268            });
 6269            Some(cx.background_spawn(async move {
 6270                futures::future::join_all(scenarios)
 6271                    .await
 6272                    .into_iter()
 6273                    .flatten()
 6274                    .collect::<Vec<_>>()
 6275            }))
 6276        })
 6277        .unwrap_or_else(|| Task::ready(vec![]))
 6278    }
 6279
 6280    fn code_actions(
 6281        &mut self,
 6282        buffer_row: u32,
 6283        window: &mut Window,
 6284        cx: &mut Context<Self>,
 6285    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 6286        let mut task = self.code_actions_task.take();
 6287        cx.spawn_in(window, async move |editor, cx| {
 6288            while let Some(prev_task) = task {
 6289                prev_task.await.log_err();
 6290                task = editor
 6291                    .update(cx, |this, _| this.code_actions_task.take())
 6292                    .ok()?;
 6293            }
 6294
 6295            editor
 6296                .update(cx, |editor, cx| {
 6297                    editor
 6298                        .available_code_actions
 6299                        .clone()
 6300                        .and_then(|(location, code_actions)| {
 6301                            let snapshot = location.buffer.read(cx).snapshot();
 6302                            let point_range = location.range.to_point(&snapshot);
 6303                            let point_range = point_range.start.row..=point_range.end.row;
 6304                            if point_range.contains(&buffer_row) {
 6305                                Some(code_actions)
 6306                            } else {
 6307                                None
 6308                            }
 6309                        })
 6310                })
 6311                .ok()
 6312                .flatten()
 6313        })
 6314    }
 6315
 6316    pub fn confirm_code_action(
 6317        &mut self,
 6318        action: &ConfirmCodeAction,
 6319        window: &mut Window,
 6320        cx: &mut Context<Self>,
 6321    ) -> Option<Task<Result<()>>> {
 6322        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6323
 6324        let actions_menu =
 6325            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 6326                menu
 6327            } else {
 6328                return None;
 6329            };
 6330
 6331        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 6332        let action = actions_menu.actions.get(action_ix)?;
 6333        let title = action.label();
 6334        let buffer = actions_menu.buffer;
 6335        let workspace = self.workspace()?;
 6336
 6337        match action {
 6338            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 6339                workspace.update(cx, |workspace, cx| {
 6340                    workspace.schedule_resolved_task(
 6341                        task_source_kind,
 6342                        resolved_task,
 6343                        false,
 6344                        window,
 6345                        cx,
 6346                    );
 6347
 6348                    Some(Task::ready(Ok(())))
 6349                })
 6350            }
 6351            CodeActionsItem::CodeAction {
 6352                excerpt_id,
 6353                action,
 6354                provider,
 6355            } => {
 6356                let apply_code_action =
 6357                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 6358                let workspace = workspace.downgrade();
 6359                Some(cx.spawn_in(window, async move |editor, cx| {
 6360                    let project_transaction = apply_code_action.await?;
 6361                    Self::open_project_transaction(
 6362                        &editor,
 6363                        workspace,
 6364                        project_transaction,
 6365                        title,
 6366                        cx,
 6367                    )
 6368                    .await
 6369                }))
 6370            }
 6371            CodeActionsItem::DebugScenario(scenario) => {
 6372                let context = actions_menu.actions.context;
 6373
 6374                workspace.update(cx, |workspace, cx| {
 6375                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 6376                    workspace.start_debug_session(
 6377                        scenario,
 6378                        context,
 6379                        Some(buffer),
 6380                        None,
 6381                        window,
 6382                        cx,
 6383                    );
 6384                });
 6385                Some(Task::ready(Ok(())))
 6386            }
 6387        }
 6388    }
 6389
 6390    pub async fn open_project_transaction(
 6391        editor: &WeakEntity<Editor>,
 6392        workspace: WeakEntity<Workspace>,
 6393        transaction: ProjectTransaction,
 6394        title: String,
 6395        cx: &mut AsyncWindowContext,
 6396    ) -> Result<()> {
 6397        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 6398        cx.update(|_, cx| {
 6399            entries.sort_unstable_by_key(|(buffer, _)| {
 6400                buffer.read(cx).file().map(|f| f.path().clone())
 6401            });
 6402        })?;
 6403        if entries.is_empty() {
 6404            return Ok(());
 6405        }
 6406
 6407        // If the project transaction's edits are all contained within this editor, then
 6408        // avoid opening a new editor to display them.
 6409
 6410        if let [(buffer, transaction)] = &*entries {
 6411            let excerpt = editor.update(cx, |editor, cx| {
 6412                editor
 6413                    .buffer()
 6414                    .read(cx)
 6415                    .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6416            })?;
 6417            if let Some((_, excerpted_buffer, excerpt_range)) = excerpt
 6418                && excerpted_buffer == *buffer
 6419            {
 6420                let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6421                    let excerpt_range = excerpt_range.to_offset(buffer);
 6422                    buffer
 6423                        .edited_ranges_for_transaction::<usize>(transaction)
 6424                        .all(|range| {
 6425                            excerpt_range.start <= range.start && excerpt_range.end >= range.end
 6426                        })
 6427                })?;
 6428
 6429                if all_edits_within_excerpt {
 6430                    return Ok(());
 6431                }
 6432            }
 6433        }
 6434
 6435        let mut ranges_to_highlight = Vec::new();
 6436        let excerpt_buffer = cx.new(|cx| {
 6437            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6438            for (buffer_handle, transaction) in &entries {
 6439                let edited_ranges = buffer_handle
 6440                    .read(cx)
 6441                    .edited_ranges_for_transaction::<Point>(transaction)
 6442                    .collect::<Vec<_>>();
 6443                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6444                    PathKey::for_buffer(buffer_handle, cx),
 6445                    buffer_handle.clone(),
 6446                    edited_ranges,
 6447                    multibuffer_context_lines(cx),
 6448                    cx,
 6449                );
 6450
 6451                ranges_to_highlight.extend(ranges);
 6452            }
 6453            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6454            multibuffer
 6455        })?;
 6456
 6457        workspace.update_in(cx, |workspace, window, cx| {
 6458            let project = workspace.project().clone();
 6459            let editor =
 6460                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6461            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6462            editor.update(cx, |editor, cx| {
 6463                editor.highlight_background::<Self>(
 6464                    &ranges_to_highlight,
 6465                    |theme| theme.colors().editor_highlighted_line_background,
 6466                    cx,
 6467                );
 6468            });
 6469        })?;
 6470
 6471        Ok(())
 6472    }
 6473
 6474    pub fn clear_code_action_providers(&mut self) {
 6475        self.code_action_providers.clear();
 6476        self.available_code_actions.take();
 6477    }
 6478
 6479    pub fn add_code_action_provider(
 6480        &mut self,
 6481        provider: Rc<dyn CodeActionProvider>,
 6482        window: &mut Window,
 6483        cx: &mut Context<Self>,
 6484    ) {
 6485        if self
 6486            .code_action_providers
 6487            .iter()
 6488            .any(|existing_provider| existing_provider.id() == provider.id())
 6489        {
 6490            return;
 6491        }
 6492
 6493        self.code_action_providers.push(provider);
 6494        self.refresh_code_actions(window, cx);
 6495    }
 6496
 6497    pub fn remove_code_action_provider(
 6498        &mut self,
 6499        id: Arc<str>,
 6500        window: &mut Window,
 6501        cx: &mut Context<Self>,
 6502    ) {
 6503        self.code_action_providers
 6504            .retain(|provider| provider.id() != id);
 6505        self.refresh_code_actions(window, cx);
 6506    }
 6507
 6508    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6509        !self.code_action_providers.is_empty()
 6510            && EditorSettings::get_global(cx).toolbar.code_actions
 6511    }
 6512
 6513    pub fn has_available_code_actions(&self) -> bool {
 6514        self.available_code_actions
 6515            .as_ref()
 6516            .is_some_and(|(_, actions)| !actions.is_empty())
 6517    }
 6518
 6519    fn render_inline_code_actions(
 6520        &self,
 6521        icon_size: ui::IconSize,
 6522        display_row: DisplayRow,
 6523        is_active: bool,
 6524        cx: &mut Context<Self>,
 6525    ) -> AnyElement {
 6526        let show_tooltip = !self.context_menu_visible();
 6527        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6528            .icon_size(icon_size)
 6529            .shape(ui::IconButtonShape::Square)
 6530            .icon_color(ui::Color::Hidden)
 6531            .toggle_state(is_active)
 6532            .when(show_tooltip, |this| {
 6533                this.tooltip({
 6534                    let focus_handle = self.focus_handle.clone();
 6535                    move |_window, cx| {
 6536                        Tooltip::for_action_in(
 6537                            "Toggle Code Actions",
 6538                            &ToggleCodeActions {
 6539                                deployed_from: None,
 6540                                quick_launch: false,
 6541                            },
 6542                            &focus_handle,
 6543                            cx,
 6544                        )
 6545                    }
 6546                })
 6547            })
 6548            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6549                window.focus(&editor.focus_handle(cx));
 6550                editor.toggle_code_actions(
 6551                    &crate::actions::ToggleCodeActions {
 6552                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6553                            display_row,
 6554                        )),
 6555                        quick_launch: false,
 6556                    },
 6557                    window,
 6558                    cx,
 6559                );
 6560            }))
 6561            .into_any_element()
 6562    }
 6563
 6564    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6565        &self.context_menu
 6566    }
 6567
 6568    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6569        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6570            cx.background_executor()
 6571                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6572                .await;
 6573
 6574            let (start_buffer, start, _, end, newest_selection) = this
 6575                .update(cx, |this, cx| {
 6576                    let newest_selection = this.selections.newest_anchor().clone();
 6577                    if newest_selection.head().diff_base_anchor.is_some() {
 6578                        return None;
 6579                    }
 6580                    let display_snapshot = this.display_snapshot(cx);
 6581                    let newest_selection_adjusted =
 6582                        this.selections.newest_adjusted(&display_snapshot);
 6583                    let buffer = this.buffer.read(cx);
 6584
 6585                    let (start_buffer, start) =
 6586                        buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6587                    let (end_buffer, end) =
 6588                        buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6589
 6590                    Some((start_buffer, start, end_buffer, end, newest_selection))
 6591                })?
 6592                .filter(|(start_buffer, _, end_buffer, _, _)| start_buffer == end_buffer)
 6593                .context(
 6594                    "Expected selection to lie in a single buffer when refreshing code actions",
 6595                )?;
 6596            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6597                let providers = this.code_action_providers.clone();
 6598                let tasks = this
 6599                    .code_action_providers
 6600                    .iter()
 6601                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6602                    .collect::<Vec<_>>();
 6603                (providers, tasks)
 6604            })?;
 6605
 6606            let mut actions = Vec::new();
 6607            for (provider, provider_actions) in
 6608                providers.into_iter().zip(future::join_all(tasks).await)
 6609            {
 6610                if let Some(provider_actions) = provider_actions.log_err() {
 6611                    actions.extend(provider_actions.into_iter().map(|action| {
 6612                        AvailableCodeAction {
 6613                            excerpt_id: newest_selection.start.excerpt_id,
 6614                            action,
 6615                            provider: provider.clone(),
 6616                        }
 6617                    }));
 6618                }
 6619            }
 6620
 6621            this.update(cx, |this, cx| {
 6622                this.available_code_actions = if actions.is_empty() {
 6623                    None
 6624                } else {
 6625                    Some((
 6626                        Location {
 6627                            buffer: start_buffer,
 6628                            range: start..end,
 6629                        },
 6630                        actions.into(),
 6631                    ))
 6632                };
 6633                cx.notify();
 6634            })
 6635        }));
 6636    }
 6637
 6638    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6639        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6640            self.show_git_blame_inline = false;
 6641
 6642            self.show_git_blame_inline_delay_task =
 6643                Some(cx.spawn_in(window, async move |this, cx| {
 6644                    cx.background_executor().timer(delay).await;
 6645
 6646                    this.update(cx, |this, cx| {
 6647                        this.show_git_blame_inline = true;
 6648                        cx.notify();
 6649                    })
 6650                    .log_err();
 6651                }));
 6652        }
 6653    }
 6654
 6655    pub fn blame_hover(&mut self, _: &BlameHover, window: &mut Window, cx: &mut Context<Self>) {
 6656        let snapshot = self.snapshot(window, cx);
 6657        let cursor = self
 6658            .selections
 6659            .newest::<Point>(&snapshot.display_snapshot)
 6660            .head();
 6661        let Some((buffer, point, _)) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)
 6662        else {
 6663            return;
 6664        };
 6665
 6666        let Some(blame) = self.blame.as_ref() else {
 6667            return;
 6668        };
 6669
 6670        let row_info = RowInfo {
 6671            buffer_id: Some(buffer.remote_id()),
 6672            buffer_row: Some(point.row),
 6673            ..Default::default()
 6674        };
 6675        let Some((buffer, blame_entry)) = blame
 6676            .update(cx, |blame, cx| blame.blame_for_rows(&[row_info], cx).next())
 6677            .flatten()
 6678        else {
 6679            return;
 6680        };
 6681
 6682        let anchor = self.selections.newest_anchor().head();
 6683        let position = self.to_pixel_point(anchor, &snapshot, window);
 6684        if let (Some(position), Some(last_bounds)) = (position, self.last_bounds) {
 6685            self.show_blame_popover(
 6686                buffer,
 6687                &blame_entry,
 6688                position + last_bounds.origin,
 6689                true,
 6690                cx,
 6691            );
 6692        };
 6693    }
 6694
 6695    fn show_blame_popover(
 6696        &mut self,
 6697        buffer: BufferId,
 6698        blame_entry: &BlameEntry,
 6699        position: gpui::Point<Pixels>,
 6700        ignore_timeout: bool,
 6701        cx: &mut Context<Self>,
 6702    ) {
 6703        if let Some(state) = &mut self.inline_blame_popover {
 6704            state.hide_task.take();
 6705        } else {
 6706            let blame_popover_delay = EditorSettings::get_global(cx).hover_popover_delay.0;
 6707            let blame_entry = blame_entry.clone();
 6708            let show_task = cx.spawn(async move |editor, cx| {
 6709                if !ignore_timeout {
 6710                    cx.background_executor()
 6711                        .timer(std::time::Duration::from_millis(blame_popover_delay))
 6712                        .await;
 6713                }
 6714                editor
 6715                    .update(cx, |editor, cx| {
 6716                        editor.inline_blame_popover_show_task.take();
 6717                        let Some(blame) = editor.blame.as_ref() else {
 6718                            return;
 6719                        };
 6720                        let blame = blame.read(cx);
 6721                        let details = blame.details_for_entry(buffer, &blame_entry);
 6722                        let markdown = cx.new(|cx| {
 6723                            Markdown::new(
 6724                                details
 6725                                    .as_ref()
 6726                                    .map(|message| message.message.clone())
 6727                                    .unwrap_or_default(),
 6728                                None,
 6729                                None,
 6730                                cx,
 6731                            )
 6732                        });
 6733                        editor.inline_blame_popover = Some(InlineBlamePopover {
 6734                            position,
 6735                            hide_task: None,
 6736                            popover_bounds: None,
 6737                            popover_state: InlineBlamePopoverState {
 6738                                scroll_handle: ScrollHandle::new(),
 6739                                commit_message: details,
 6740                                markdown,
 6741                            },
 6742                            keyboard_grace: ignore_timeout,
 6743                        });
 6744                        cx.notify();
 6745                    })
 6746                    .ok();
 6747            });
 6748            self.inline_blame_popover_show_task = Some(show_task);
 6749        }
 6750    }
 6751
 6752    fn hide_blame_popover(&mut self, ignore_timeout: bool, cx: &mut Context<Self>) -> bool {
 6753        self.inline_blame_popover_show_task.take();
 6754        if let Some(state) = &mut self.inline_blame_popover {
 6755            let hide_task = cx.spawn(async move |editor, cx| {
 6756                if !ignore_timeout {
 6757                    cx.background_executor()
 6758                        .timer(std::time::Duration::from_millis(100))
 6759                        .await;
 6760                }
 6761                editor
 6762                    .update(cx, |editor, cx| {
 6763                        editor.inline_blame_popover.take();
 6764                        cx.notify();
 6765                    })
 6766                    .ok();
 6767            });
 6768            state.hide_task = Some(hide_task);
 6769            true
 6770        } else {
 6771            false
 6772        }
 6773    }
 6774
 6775    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 6776        if self.pending_rename.is_some() {
 6777            return None;
 6778        }
 6779
 6780        let provider = self.semantics_provider.clone()?;
 6781        let buffer = self.buffer.read(cx);
 6782        let newest_selection = self.selections.newest_anchor().clone();
 6783        let cursor_position = newest_selection.head();
 6784        let (cursor_buffer, cursor_buffer_position) =
 6785            buffer.text_anchor_for_position(cursor_position, cx)?;
 6786        let (tail_buffer, tail_buffer_position) =
 6787            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 6788        if cursor_buffer != tail_buffer {
 6789            return None;
 6790        }
 6791
 6792        let snapshot = cursor_buffer.read(cx).snapshot();
 6793        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position, None);
 6794        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position, None);
 6795        if start_word_range != end_word_range {
 6796            self.document_highlights_task.take();
 6797            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6798            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6799            return None;
 6800        }
 6801
 6802        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce.0;
 6803        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6804            cx.background_executor()
 6805                .timer(Duration::from_millis(debounce))
 6806                .await;
 6807
 6808            let highlights = if let Some(highlights) = cx
 6809                .update(|cx| {
 6810                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 6811                })
 6812                .ok()
 6813                .flatten()
 6814            {
 6815                highlights.await.log_err()
 6816            } else {
 6817                None
 6818            };
 6819
 6820            if let Some(highlights) = highlights {
 6821                this.update(cx, |this, cx| {
 6822                    if this.pending_rename.is_some() {
 6823                        return;
 6824                    }
 6825
 6826                    let buffer = this.buffer.read(cx);
 6827                    if buffer
 6828                        .text_anchor_for_position(cursor_position, cx)
 6829                        .is_none_or(|(buffer, _)| buffer != cursor_buffer)
 6830                    {
 6831                        return;
 6832                    }
 6833
 6834                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 6835                    let mut write_ranges = Vec::new();
 6836                    let mut read_ranges = Vec::new();
 6837                    for highlight in highlights {
 6838                        let buffer_id = cursor_buffer.read(cx).remote_id();
 6839                        for (excerpt_id, excerpt_range) in buffer.excerpts_for_buffer(buffer_id, cx)
 6840                        {
 6841                            let start = highlight
 6842                                .range
 6843                                .start
 6844                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 6845                            let end = highlight
 6846                                .range
 6847                                .end
 6848                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6849                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6850                                continue;
 6851                            }
 6852
 6853                            let range =
 6854                                Anchor::range_in_buffer(excerpt_id, buffer_id, *start..*end);
 6855                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 6856                                write_ranges.push(range);
 6857                            } else {
 6858                                read_ranges.push(range);
 6859                            }
 6860                        }
 6861                    }
 6862
 6863                    this.highlight_background::<DocumentHighlightRead>(
 6864                        &read_ranges,
 6865                        |theme| theme.colors().editor_document_highlight_read_background,
 6866                        cx,
 6867                    );
 6868                    this.highlight_background::<DocumentHighlightWrite>(
 6869                        &write_ranges,
 6870                        |theme| theme.colors().editor_document_highlight_write_background,
 6871                        cx,
 6872                    );
 6873                    cx.notify();
 6874                })
 6875                .log_err();
 6876            }
 6877        }));
 6878        None
 6879    }
 6880
 6881    fn prepare_highlight_query_from_selection(
 6882        &mut self,
 6883        window: &Window,
 6884        cx: &mut Context<Editor>,
 6885    ) -> Option<(String, Range<Anchor>)> {
 6886        if matches!(self.mode, EditorMode::SingleLine) {
 6887            return None;
 6888        }
 6889        if !EditorSettings::get_global(cx).selection_highlight {
 6890            return None;
 6891        }
 6892        if self.selections.count() != 1 || self.selections.line_mode() {
 6893            return None;
 6894        }
 6895        let snapshot = self.snapshot(window, cx);
 6896        let selection = self.selections.newest::<Point>(&snapshot);
 6897        // If the selection spans multiple rows OR it is empty
 6898        if selection.start.row != selection.end.row
 6899            || selection.start.column == selection.end.column
 6900        {
 6901            return None;
 6902        }
 6903        let selection_anchor_range = selection.range().to_anchors(snapshot.buffer_snapshot());
 6904        let query = snapshot
 6905            .buffer_snapshot()
 6906            .text_for_range(selection_anchor_range.clone())
 6907            .collect::<String>();
 6908        if query.trim().is_empty() {
 6909            return None;
 6910        }
 6911        Some((query, selection_anchor_range))
 6912    }
 6913
 6914    fn update_selection_occurrence_highlights(
 6915        &mut self,
 6916        query_text: String,
 6917        query_range: Range<Anchor>,
 6918        multi_buffer_range_to_query: Range<Point>,
 6919        use_debounce: bool,
 6920        window: &mut Window,
 6921        cx: &mut Context<Editor>,
 6922    ) -> Task<()> {
 6923        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6924        cx.spawn_in(window, async move |editor, cx| {
 6925            if use_debounce {
 6926                cx.background_executor()
 6927                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 6928                    .await;
 6929            }
 6930            let match_task = cx.background_spawn(async move {
 6931                let buffer_ranges = multi_buffer_snapshot
 6932                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 6933                    .into_iter()
 6934                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 6935                let mut match_ranges = Vec::new();
 6936                let Ok(regex) = project::search::SearchQuery::text(
 6937                    query_text.clone(),
 6938                    false,
 6939                    false,
 6940                    false,
 6941                    Default::default(),
 6942                    Default::default(),
 6943                    false,
 6944                    None,
 6945                ) else {
 6946                    return Vec::default();
 6947                };
 6948                let query_range = query_range.to_anchors(&multi_buffer_snapshot);
 6949                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 6950                    match_ranges.extend(
 6951                        regex
 6952                            .search(buffer_snapshot, Some(search_range.clone()))
 6953                            .await
 6954                            .into_iter()
 6955                            .filter_map(|match_range| {
 6956                                let match_start = buffer_snapshot
 6957                                    .anchor_after(search_range.start + match_range.start);
 6958                                let match_end = buffer_snapshot
 6959                                    .anchor_before(search_range.start + match_range.end);
 6960                                let match_anchor_range = Anchor::range_in_buffer(
 6961                                    excerpt_id,
 6962                                    buffer_snapshot.remote_id(),
 6963                                    match_start..match_end,
 6964                                );
 6965                                (match_anchor_range != query_range).then_some(match_anchor_range)
 6966                            }),
 6967                    );
 6968                }
 6969                match_ranges
 6970            });
 6971            let match_ranges = match_task.await;
 6972            editor
 6973                .update_in(cx, |editor, _, cx| {
 6974                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 6975                    if !match_ranges.is_empty() {
 6976                        editor.highlight_background::<SelectedTextHighlight>(
 6977                            &match_ranges,
 6978                            |theme| theme.colors().editor_document_highlight_bracket_background,
 6979                            cx,
 6980                        )
 6981                    }
 6982                })
 6983                .log_err();
 6984        })
 6985    }
 6986
 6987    fn refresh_single_line_folds(&mut self, window: &mut Window, cx: &mut Context<Editor>) {
 6988        struct NewlineFold;
 6989        let type_id = std::any::TypeId::of::<NewlineFold>();
 6990        if !self.mode.is_single_line() {
 6991            return;
 6992        }
 6993        let snapshot = self.snapshot(window, cx);
 6994        if snapshot.buffer_snapshot().max_point().row == 0 {
 6995            return;
 6996        }
 6997        let task = cx.background_spawn(async move {
 6998            let new_newlines = snapshot
 6999                .buffer_chars_at(0)
 7000                .filter_map(|(c, i)| {
 7001                    if c == '\n' {
 7002                        Some(
 7003                            snapshot.buffer_snapshot().anchor_after(i)
 7004                                ..snapshot.buffer_snapshot().anchor_before(i + 1),
 7005                        )
 7006                    } else {
 7007                        None
 7008                    }
 7009                })
 7010                .collect::<Vec<_>>();
 7011            let existing_newlines = snapshot
 7012                .folds_in_range(0..snapshot.buffer_snapshot().len())
 7013                .filter_map(|fold| {
 7014                    if fold.placeholder.type_tag == Some(type_id) {
 7015                        Some(fold.range.start..fold.range.end)
 7016                    } else {
 7017                        None
 7018                    }
 7019                })
 7020                .collect::<Vec<_>>();
 7021
 7022            (new_newlines, existing_newlines)
 7023        });
 7024        self.folding_newlines = cx.spawn(async move |this, cx| {
 7025            let (new_newlines, existing_newlines) = task.await;
 7026            if new_newlines == existing_newlines {
 7027                return;
 7028            }
 7029            let placeholder = FoldPlaceholder {
 7030                render: Arc::new(move |_, _, cx| {
 7031                    div()
 7032                        .bg(cx.theme().status().hint_background)
 7033                        .border_b_1()
 7034                        .size_full()
 7035                        .font(ThemeSettings::get_global(cx).buffer_font.clone())
 7036                        .border_color(cx.theme().status().hint)
 7037                        .child("\\n")
 7038                        .into_any()
 7039                }),
 7040                constrain_width: false,
 7041                merge_adjacent: false,
 7042                type_tag: Some(type_id),
 7043            };
 7044            let creases = new_newlines
 7045                .into_iter()
 7046                .map(|range| Crease::simple(range, placeholder.clone()))
 7047                .collect();
 7048            this.update(cx, |this, cx| {
 7049                this.display_map.update(cx, |display_map, cx| {
 7050                    display_map.remove_folds_with_type(existing_newlines, type_id, cx);
 7051                    display_map.fold(creases, cx);
 7052                });
 7053            })
 7054            .ok();
 7055        });
 7056    }
 7057
 7058    fn refresh_selected_text_highlights(
 7059        &mut self,
 7060        on_buffer_edit: bool,
 7061        window: &mut Window,
 7062        cx: &mut Context<Editor>,
 7063    ) {
 7064        let Some((query_text, query_range)) =
 7065            self.prepare_highlight_query_from_selection(window, cx)
 7066        else {
 7067            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 7068            self.quick_selection_highlight_task.take();
 7069            self.debounced_selection_highlight_task.take();
 7070            return;
 7071        };
 7072        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 7073        if on_buffer_edit
 7074            || self
 7075                .quick_selection_highlight_task
 7076                .as_ref()
 7077                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7078        {
 7079            let multi_buffer_visible_start = self
 7080                .scroll_manager
 7081                .anchor()
 7082                .anchor
 7083                .to_point(&multi_buffer_snapshot);
 7084            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 7085                multi_buffer_visible_start
 7086                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 7087                Bias::Left,
 7088            );
 7089            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 7090            self.quick_selection_highlight_task = Some((
 7091                query_range.clone(),
 7092                self.update_selection_occurrence_highlights(
 7093                    query_text.clone(),
 7094                    query_range.clone(),
 7095                    multi_buffer_visible_range,
 7096                    false,
 7097                    window,
 7098                    cx,
 7099                ),
 7100            ));
 7101        }
 7102        if on_buffer_edit
 7103            || self
 7104                .debounced_selection_highlight_task
 7105                .as_ref()
 7106                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7107        {
 7108            let multi_buffer_start = multi_buffer_snapshot
 7109                .anchor_before(0)
 7110                .to_point(&multi_buffer_snapshot);
 7111            let multi_buffer_end = multi_buffer_snapshot
 7112                .anchor_after(multi_buffer_snapshot.len())
 7113                .to_point(&multi_buffer_snapshot);
 7114            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 7115            self.debounced_selection_highlight_task = Some((
 7116                query_range.clone(),
 7117                self.update_selection_occurrence_highlights(
 7118                    query_text,
 7119                    query_range,
 7120                    multi_buffer_full_range,
 7121                    true,
 7122                    window,
 7123                    cx,
 7124                ),
 7125            ));
 7126        }
 7127    }
 7128
 7129    pub fn refresh_edit_prediction(
 7130        &mut self,
 7131        debounce: bool,
 7132        user_requested: bool,
 7133        window: &mut Window,
 7134        cx: &mut Context<Self>,
 7135    ) -> Option<()> {
 7136        if DisableAiSettings::get_global(cx).disable_ai {
 7137            return None;
 7138        }
 7139
 7140        let provider = self.edit_prediction_provider()?;
 7141        let cursor = self.selections.newest_anchor().head();
 7142        let (buffer, cursor_buffer_position) =
 7143            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7144
 7145        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 7146            self.discard_edit_prediction(false, cx);
 7147            return None;
 7148        }
 7149
 7150        self.update_visible_edit_prediction(window, cx);
 7151
 7152        if !user_requested
 7153            && (!self.should_show_edit_predictions()
 7154                || !self.is_focused(window)
 7155                || buffer.read(cx).is_empty())
 7156        {
 7157            self.discard_edit_prediction(false, cx);
 7158            return None;
 7159        }
 7160
 7161        provider.refresh(buffer, cursor_buffer_position, debounce, cx);
 7162        Some(())
 7163    }
 7164
 7165    fn show_edit_predictions_in_menu(&self) -> bool {
 7166        match self.edit_prediction_settings {
 7167            EditPredictionSettings::Disabled => false,
 7168            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 7169        }
 7170    }
 7171
 7172    pub fn edit_predictions_enabled(&self) -> bool {
 7173        match self.edit_prediction_settings {
 7174            EditPredictionSettings::Disabled => false,
 7175            EditPredictionSettings::Enabled { .. } => true,
 7176        }
 7177    }
 7178
 7179    fn edit_prediction_requires_modifier(&self) -> bool {
 7180        match self.edit_prediction_settings {
 7181            EditPredictionSettings::Disabled => false,
 7182            EditPredictionSettings::Enabled {
 7183                preview_requires_modifier,
 7184                ..
 7185            } => preview_requires_modifier,
 7186        }
 7187    }
 7188
 7189    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 7190        if self.edit_prediction_provider.is_none() || DisableAiSettings::get_global(cx).disable_ai {
 7191            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7192            self.discard_edit_prediction(false, cx);
 7193        } else {
 7194            let selection = self.selections.newest_anchor();
 7195            let cursor = selection.head();
 7196
 7197            if let Some((buffer, cursor_buffer_position)) =
 7198                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7199            {
 7200                self.edit_prediction_settings =
 7201                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7202            }
 7203        }
 7204    }
 7205
 7206    fn edit_prediction_settings_at_position(
 7207        &self,
 7208        buffer: &Entity<Buffer>,
 7209        buffer_position: language::Anchor,
 7210        cx: &App,
 7211    ) -> EditPredictionSettings {
 7212        if !self.mode.is_full()
 7213            || !self.show_edit_predictions_override.unwrap_or(true)
 7214            || self.edit_predictions_disabled_in_scope(buffer, buffer_position, cx)
 7215        {
 7216            return EditPredictionSettings::Disabled;
 7217        }
 7218
 7219        let buffer = buffer.read(cx);
 7220
 7221        let file = buffer.file();
 7222
 7223        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 7224            return EditPredictionSettings::Disabled;
 7225        };
 7226
 7227        let by_provider = matches!(
 7228            self.menu_edit_predictions_policy,
 7229            MenuEditPredictionsPolicy::ByProvider
 7230        );
 7231
 7232        let show_in_menu = by_provider
 7233            && self
 7234                .edit_prediction_provider
 7235                .as_ref()
 7236                .is_some_and(|provider| provider.provider.show_completions_in_menu());
 7237
 7238        let preview_requires_modifier =
 7239            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 7240
 7241        EditPredictionSettings::Enabled {
 7242            show_in_menu,
 7243            preview_requires_modifier,
 7244        }
 7245    }
 7246
 7247    fn should_show_edit_predictions(&self) -> bool {
 7248        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 7249    }
 7250
 7251    pub fn edit_prediction_preview_is_active(&self) -> bool {
 7252        matches!(
 7253            self.edit_prediction_preview,
 7254            EditPredictionPreview::Active { .. }
 7255        )
 7256    }
 7257
 7258    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 7259        let cursor = self.selections.newest_anchor().head();
 7260        if let Some((buffer, cursor_position)) =
 7261            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7262        {
 7263            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 7264        } else {
 7265            false
 7266        }
 7267    }
 7268
 7269    pub fn supports_minimap(&self, cx: &App) -> bool {
 7270        !self.minimap_visibility.disabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton
 7271    }
 7272
 7273    fn edit_predictions_enabled_in_buffer(
 7274        &self,
 7275        buffer: &Entity<Buffer>,
 7276        buffer_position: language::Anchor,
 7277        cx: &App,
 7278    ) -> bool {
 7279        maybe!({
 7280            if self.read_only(cx) {
 7281                return Some(false);
 7282            }
 7283            let provider = self.edit_prediction_provider()?;
 7284            if !provider.is_enabled(buffer, buffer_position, cx) {
 7285                return Some(false);
 7286            }
 7287            let buffer = buffer.read(cx);
 7288            let Some(file) = buffer.file() else {
 7289                return Some(true);
 7290            };
 7291            let settings = all_language_settings(Some(file), cx);
 7292            Some(settings.edit_predictions_enabled_for_file(file, cx))
 7293        })
 7294        .unwrap_or(false)
 7295    }
 7296
 7297    fn cycle_edit_prediction(
 7298        &mut self,
 7299        direction: Direction,
 7300        window: &mut Window,
 7301        cx: &mut Context<Self>,
 7302    ) -> Option<()> {
 7303        let provider = self.edit_prediction_provider()?;
 7304        let cursor = self.selections.newest_anchor().head();
 7305        let (buffer, cursor_buffer_position) =
 7306            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7307        if self.edit_predictions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 7308            return None;
 7309        }
 7310
 7311        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 7312        self.update_visible_edit_prediction(window, cx);
 7313
 7314        Some(())
 7315    }
 7316
 7317    pub fn show_edit_prediction(
 7318        &mut self,
 7319        _: &ShowEditPrediction,
 7320        window: &mut Window,
 7321        cx: &mut Context<Self>,
 7322    ) {
 7323        if !self.has_active_edit_prediction() {
 7324            self.refresh_edit_prediction(false, true, window, cx);
 7325            return;
 7326        }
 7327
 7328        self.update_visible_edit_prediction(window, cx);
 7329    }
 7330
 7331    pub fn display_cursor_names(
 7332        &mut self,
 7333        _: &DisplayCursorNames,
 7334        window: &mut Window,
 7335        cx: &mut Context<Self>,
 7336    ) {
 7337        self.show_cursor_names(window, cx);
 7338    }
 7339
 7340    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7341        self.show_cursor_names = true;
 7342        cx.notify();
 7343        cx.spawn_in(window, async move |this, cx| {
 7344            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 7345            this.update(cx, |this, cx| {
 7346                this.show_cursor_names = false;
 7347                cx.notify()
 7348            })
 7349            .ok()
 7350        })
 7351        .detach();
 7352    }
 7353
 7354    pub fn next_edit_prediction(
 7355        &mut self,
 7356        _: &NextEditPrediction,
 7357        window: &mut Window,
 7358        cx: &mut Context<Self>,
 7359    ) {
 7360        if self.has_active_edit_prediction() {
 7361            self.cycle_edit_prediction(Direction::Next, window, cx);
 7362        } else {
 7363            let is_copilot_disabled = self
 7364                .refresh_edit_prediction(false, true, window, cx)
 7365                .is_none();
 7366            if is_copilot_disabled {
 7367                cx.propagate();
 7368            }
 7369        }
 7370    }
 7371
 7372    pub fn previous_edit_prediction(
 7373        &mut self,
 7374        _: &PreviousEditPrediction,
 7375        window: &mut Window,
 7376        cx: &mut Context<Self>,
 7377    ) {
 7378        if self.has_active_edit_prediction() {
 7379            self.cycle_edit_prediction(Direction::Prev, window, cx);
 7380        } else {
 7381            let is_copilot_disabled = self
 7382                .refresh_edit_prediction(false, true, window, cx)
 7383                .is_none();
 7384            if is_copilot_disabled {
 7385                cx.propagate();
 7386            }
 7387        }
 7388    }
 7389
 7390    pub fn accept_edit_prediction(
 7391        &mut self,
 7392        _: &AcceptEditPrediction,
 7393        window: &mut Window,
 7394        cx: &mut Context<Self>,
 7395    ) {
 7396        if self.show_edit_predictions_in_menu() {
 7397            self.hide_context_menu(window, cx);
 7398        }
 7399
 7400        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7401            return;
 7402        };
 7403
 7404        match &active_edit_prediction.completion {
 7405            EditPrediction::MoveWithin { target, .. } => {
 7406                let target = *target;
 7407
 7408                if let Some(position_map) = &self.last_position_map {
 7409                    if position_map
 7410                        .visible_row_range
 7411                        .contains(&target.to_display_point(&position_map.snapshot).row())
 7412                        || !self.edit_prediction_requires_modifier()
 7413                    {
 7414                        self.unfold_ranges(&[target..target], true, false, cx);
 7415                        // Note that this is also done in vim's handler of the Tab action.
 7416                        self.change_selections(
 7417                            SelectionEffects::scroll(Autoscroll::newest()),
 7418                            window,
 7419                            cx,
 7420                            |selections| {
 7421                                selections.select_anchor_ranges([target..target]);
 7422                            },
 7423                        );
 7424                        self.clear_row_highlights::<EditPredictionPreview>();
 7425
 7426                        self.edit_prediction_preview
 7427                            .set_previous_scroll_position(None);
 7428                    } else {
 7429                        self.edit_prediction_preview
 7430                            .set_previous_scroll_position(Some(
 7431                                position_map.snapshot.scroll_anchor,
 7432                            ));
 7433
 7434                        self.highlight_rows::<EditPredictionPreview>(
 7435                            target..target,
 7436                            cx.theme().colors().editor_highlighted_line_background,
 7437                            RowHighlightOptions {
 7438                                autoscroll: true,
 7439                                ..Default::default()
 7440                            },
 7441                            cx,
 7442                        );
 7443                        self.request_autoscroll(Autoscroll::fit(), cx);
 7444                    }
 7445                }
 7446            }
 7447            EditPrediction::MoveOutside { snapshot, target } => {
 7448                if let Some(workspace) = self.workspace() {
 7449                    Self::open_editor_at_anchor(snapshot, *target, &workspace, window, cx)
 7450                        .detach_and_log_err(cx);
 7451                }
 7452            }
 7453            EditPrediction::Edit { edits, .. } => {
 7454                self.report_edit_prediction_event(
 7455                    active_edit_prediction.completion_id.clone(),
 7456                    true,
 7457                    cx,
 7458                );
 7459
 7460                if let Some(provider) = self.edit_prediction_provider() {
 7461                    provider.accept(cx);
 7462                }
 7463
 7464                // Store the transaction ID and selections before applying the edit
 7465                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 7466
 7467                let snapshot = self.buffer.read(cx).snapshot(cx);
 7468                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 7469
 7470                self.buffer.update(cx, |buffer, cx| {
 7471                    buffer.edit(edits.iter().cloned(), None, cx)
 7472                });
 7473
 7474                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 7475                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 7476                });
 7477
 7478                let selections = self.selections.disjoint_anchors_arc();
 7479                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 7480                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 7481                    if has_new_transaction {
 7482                        self.selection_history
 7483                            .insert_transaction(transaction_id_now, selections);
 7484                    }
 7485                }
 7486
 7487                self.update_visible_edit_prediction(window, cx);
 7488                if self.active_edit_prediction.is_none() {
 7489                    self.refresh_edit_prediction(true, true, window, cx);
 7490                }
 7491
 7492                cx.notify();
 7493            }
 7494        }
 7495
 7496        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 7497    }
 7498
 7499    pub fn accept_partial_edit_prediction(
 7500        &mut self,
 7501        _: &AcceptPartialEditPrediction,
 7502        window: &mut Window,
 7503        cx: &mut Context<Self>,
 7504    ) {
 7505        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7506            return;
 7507        };
 7508        if self.selections.count() != 1 {
 7509            return;
 7510        }
 7511
 7512        match &active_edit_prediction.completion {
 7513            EditPrediction::MoveWithin { target, .. } => {
 7514                let target = *target;
 7515                self.change_selections(
 7516                    SelectionEffects::scroll(Autoscroll::newest()),
 7517                    window,
 7518                    cx,
 7519                    |selections| {
 7520                        selections.select_anchor_ranges([target..target]);
 7521                    },
 7522                );
 7523            }
 7524            EditPrediction::MoveOutside { snapshot, target } => {
 7525                if let Some(workspace) = self.workspace() {
 7526                    Self::open_editor_at_anchor(snapshot, *target, &workspace, window, cx)
 7527                        .detach_and_log_err(cx);
 7528                }
 7529            }
 7530            EditPrediction::Edit { edits, .. } => {
 7531                self.report_edit_prediction_event(
 7532                    active_edit_prediction.completion_id.clone(),
 7533                    true,
 7534                    cx,
 7535                );
 7536
 7537                // Find an insertion that starts at the cursor position.
 7538                let snapshot = self.buffer.read(cx).snapshot(cx);
 7539                let cursor_offset = self
 7540                    .selections
 7541                    .newest::<usize>(&self.display_snapshot(cx))
 7542                    .head();
 7543                let insertion = edits.iter().find_map(|(range, text)| {
 7544                    let range = range.to_offset(&snapshot);
 7545                    if range.is_empty() && range.start == cursor_offset {
 7546                        Some(text)
 7547                    } else {
 7548                        None
 7549                    }
 7550                });
 7551
 7552                if let Some(text) = insertion {
 7553                    let mut partial_completion = text
 7554                        .chars()
 7555                        .by_ref()
 7556                        .take_while(|c| c.is_alphabetic())
 7557                        .collect::<String>();
 7558                    if partial_completion.is_empty() {
 7559                        partial_completion = text
 7560                            .chars()
 7561                            .by_ref()
 7562                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7563                            .collect::<String>();
 7564                    }
 7565
 7566                    cx.emit(EditorEvent::InputHandled {
 7567                        utf16_range_to_replace: None,
 7568                        text: partial_completion.clone().into(),
 7569                    });
 7570
 7571                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 7572
 7573                    self.refresh_edit_prediction(true, true, window, cx);
 7574                    cx.notify();
 7575                } else {
 7576                    self.accept_edit_prediction(&Default::default(), window, cx);
 7577                }
 7578            }
 7579        }
 7580    }
 7581
 7582    fn discard_edit_prediction(
 7583        &mut self,
 7584        should_report_edit_prediction_event: bool,
 7585        cx: &mut Context<Self>,
 7586    ) -> bool {
 7587        if should_report_edit_prediction_event {
 7588            let completion_id = self
 7589                .active_edit_prediction
 7590                .as_ref()
 7591                .and_then(|active_completion| active_completion.completion_id.clone());
 7592
 7593            self.report_edit_prediction_event(completion_id, false, cx);
 7594        }
 7595
 7596        if let Some(provider) = self.edit_prediction_provider() {
 7597            provider.discard(cx);
 7598        }
 7599
 7600        self.take_active_edit_prediction(cx)
 7601    }
 7602
 7603    fn report_edit_prediction_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7604        let Some(provider) = self.edit_prediction_provider() else {
 7605            return;
 7606        };
 7607
 7608        let Some((_, buffer, _)) = self
 7609            .buffer
 7610            .read(cx)
 7611            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7612        else {
 7613            return;
 7614        };
 7615
 7616        let extension = buffer
 7617            .read(cx)
 7618            .file()
 7619            .and_then(|file| Some(file.path().extension()?.to_string()));
 7620
 7621        let event_type = match accepted {
 7622            true => "Edit Prediction Accepted",
 7623            false => "Edit Prediction Discarded",
 7624        };
 7625        telemetry::event!(
 7626            event_type,
 7627            provider = provider.name(),
 7628            prediction_id = id,
 7629            suggestion_accepted = accepted,
 7630            file_extension = extension,
 7631        );
 7632    }
 7633
 7634    fn open_editor_at_anchor(
 7635        snapshot: &language::BufferSnapshot,
 7636        target: language::Anchor,
 7637        workspace: &Entity<Workspace>,
 7638        window: &mut Window,
 7639        cx: &mut App,
 7640    ) -> Task<Result<()>> {
 7641        workspace.update(cx, |workspace, cx| {
 7642            let path = snapshot.file().map(|file| file.full_path(cx));
 7643            let Some(path) =
 7644                path.and_then(|path| workspace.project().read(cx).find_project_path(path, cx))
 7645            else {
 7646                return Task::ready(Err(anyhow::anyhow!("Project path not found")));
 7647            };
 7648            let target = text::ToPoint::to_point(&target, snapshot);
 7649            let item = workspace.open_path(path, None, true, window, cx);
 7650            window.spawn(cx, async move |cx| {
 7651                let Some(editor) = item.await?.downcast::<Editor>() else {
 7652                    return Ok(());
 7653                };
 7654                editor
 7655                    .update_in(cx, |editor, window, cx| {
 7656                        editor.go_to_singleton_buffer_point(target, window, cx);
 7657                    })
 7658                    .ok();
 7659                anyhow::Ok(())
 7660            })
 7661        })
 7662    }
 7663
 7664    pub fn has_active_edit_prediction(&self) -> bool {
 7665        self.active_edit_prediction.is_some()
 7666    }
 7667
 7668    fn take_active_edit_prediction(&mut self, cx: &mut Context<Self>) -> bool {
 7669        let Some(active_edit_prediction) = self.active_edit_prediction.take() else {
 7670            return false;
 7671        };
 7672
 7673        self.splice_inlays(&active_edit_prediction.inlay_ids, Default::default(), cx);
 7674        self.clear_highlights::<EditPredictionHighlight>(cx);
 7675        self.stale_edit_prediction_in_menu = Some(active_edit_prediction);
 7676        true
 7677    }
 7678
 7679    /// Returns true when we're displaying the edit prediction popover below the cursor
 7680    /// like we are not previewing and the LSP autocomplete menu is visible
 7681    /// or we are in `when_holding_modifier` mode.
 7682    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7683        if self.edit_prediction_preview_is_active()
 7684            || !self.show_edit_predictions_in_menu()
 7685            || !self.edit_predictions_enabled()
 7686        {
 7687            return false;
 7688        }
 7689
 7690        if self.has_visible_completions_menu() {
 7691            return true;
 7692        }
 7693
 7694        has_completion && self.edit_prediction_requires_modifier()
 7695    }
 7696
 7697    fn handle_modifiers_changed(
 7698        &mut self,
 7699        modifiers: Modifiers,
 7700        position_map: &PositionMap,
 7701        window: &mut Window,
 7702        cx: &mut Context<Self>,
 7703    ) {
 7704        // Ensure that the edit prediction preview is updated, even when not
 7705        // enabled, if there's an active edit prediction preview.
 7706        if self.show_edit_predictions_in_menu()
 7707            || matches!(
 7708                self.edit_prediction_preview,
 7709                EditPredictionPreview::Active { .. }
 7710            )
 7711        {
 7712            self.update_edit_prediction_preview(&modifiers, window, cx);
 7713        }
 7714
 7715        self.update_selection_mode(&modifiers, position_map, window, cx);
 7716
 7717        let mouse_position = window.mouse_position();
 7718        if !position_map.text_hitbox.is_hovered(window) {
 7719            return;
 7720        }
 7721
 7722        self.update_hovered_link(
 7723            position_map.point_for_position(mouse_position),
 7724            &position_map.snapshot,
 7725            modifiers,
 7726            window,
 7727            cx,
 7728        )
 7729    }
 7730
 7731    fn is_cmd_or_ctrl_pressed(modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7732        match EditorSettings::get_global(cx).multi_cursor_modifier {
 7733            MultiCursorModifier::Alt => modifiers.secondary(),
 7734            MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 7735        }
 7736    }
 7737
 7738    fn is_alt_pressed(modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7739        match EditorSettings::get_global(cx).multi_cursor_modifier {
 7740            MultiCursorModifier::Alt => modifiers.alt,
 7741            MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 7742        }
 7743    }
 7744
 7745    fn columnar_selection_mode(
 7746        modifiers: &Modifiers,
 7747        cx: &mut Context<Self>,
 7748    ) -> Option<ColumnarMode> {
 7749        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 7750            if Self::is_cmd_or_ctrl_pressed(modifiers, cx) {
 7751                Some(ColumnarMode::FromMouse)
 7752            } else if Self::is_alt_pressed(modifiers, cx) {
 7753                Some(ColumnarMode::FromSelection)
 7754            } else {
 7755                None
 7756            }
 7757        } else {
 7758            None
 7759        }
 7760    }
 7761
 7762    fn update_selection_mode(
 7763        &mut self,
 7764        modifiers: &Modifiers,
 7765        position_map: &PositionMap,
 7766        window: &mut Window,
 7767        cx: &mut Context<Self>,
 7768    ) {
 7769        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 7770            return;
 7771        };
 7772        if self.selections.pending_anchor().is_none() {
 7773            return;
 7774        }
 7775
 7776        let mouse_position = window.mouse_position();
 7777        let point_for_position = position_map.point_for_position(mouse_position);
 7778        let position = point_for_position.previous_valid;
 7779
 7780        self.select(
 7781            SelectPhase::BeginColumnar {
 7782                position,
 7783                reset: false,
 7784                mode,
 7785                goal_column: point_for_position.exact_unclipped.column(),
 7786            },
 7787            window,
 7788            cx,
 7789        );
 7790    }
 7791
 7792    fn update_edit_prediction_preview(
 7793        &mut self,
 7794        modifiers: &Modifiers,
 7795        window: &mut Window,
 7796        cx: &mut Context<Self>,
 7797    ) {
 7798        let mut modifiers_held = false;
 7799        if let Some(accept_keystroke) = self
 7800            .accept_edit_prediction_keybind(false, window, cx)
 7801            .keystroke()
 7802        {
 7803            modifiers_held = modifiers_held
 7804                || (accept_keystroke.modifiers() == modifiers
 7805                    && accept_keystroke.modifiers().modified());
 7806        };
 7807        if let Some(accept_partial_keystroke) = self
 7808            .accept_edit_prediction_keybind(true, window, cx)
 7809            .keystroke()
 7810        {
 7811            modifiers_held = modifiers_held
 7812                || (accept_partial_keystroke.modifiers() == modifiers
 7813                    && accept_partial_keystroke.modifiers().modified());
 7814        }
 7815
 7816        if modifiers_held {
 7817            if matches!(
 7818                self.edit_prediction_preview,
 7819                EditPredictionPreview::Inactive { .. }
 7820            ) {
 7821                self.edit_prediction_preview = EditPredictionPreview::Active {
 7822                    previous_scroll_position: None,
 7823                    since: Instant::now(),
 7824                };
 7825
 7826                self.update_visible_edit_prediction(window, cx);
 7827                cx.notify();
 7828            }
 7829        } else if let EditPredictionPreview::Active {
 7830            previous_scroll_position,
 7831            since,
 7832        } = self.edit_prediction_preview
 7833        {
 7834            if let (Some(previous_scroll_position), Some(position_map)) =
 7835                (previous_scroll_position, self.last_position_map.as_ref())
 7836            {
 7837                self.set_scroll_position(
 7838                    previous_scroll_position
 7839                        .scroll_position(&position_map.snapshot.display_snapshot),
 7840                    window,
 7841                    cx,
 7842                );
 7843            }
 7844
 7845            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 7846                released_too_fast: since.elapsed() < Duration::from_millis(200),
 7847            };
 7848            self.clear_row_highlights::<EditPredictionPreview>();
 7849            self.update_visible_edit_prediction(window, cx);
 7850            cx.notify();
 7851        }
 7852    }
 7853
 7854    fn update_visible_edit_prediction(
 7855        &mut self,
 7856        _window: &mut Window,
 7857        cx: &mut Context<Self>,
 7858    ) -> Option<()> {
 7859        if DisableAiSettings::get_global(cx).disable_ai {
 7860            return None;
 7861        }
 7862
 7863        if self.ime_transaction.is_some() {
 7864            self.discard_edit_prediction(false, cx);
 7865            return None;
 7866        }
 7867
 7868        let selection = self.selections.newest_anchor();
 7869        let cursor = selection.head();
 7870        let multibuffer = self.buffer.read(cx).snapshot(cx);
 7871        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 7872        let excerpt_id = cursor.excerpt_id;
 7873
 7874        let show_in_menu = self.show_edit_predictions_in_menu();
 7875        let completions_menu_has_precedence = !show_in_menu
 7876            && (self.context_menu.borrow().is_some()
 7877                || (!self.completion_tasks.is_empty() && !self.has_active_edit_prediction()));
 7878
 7879        if completions_menu_has_precedence
 7880            || !offset_selection.is_empty()
 7881            || self
 7882                .active_edit_prediction
 7883                .as_ref()
 7884                .is_some_and(|completion| {
 7885                    let Some(invalidation_range) = completion.invalidation_range.as_ref() else {
 7886                        return false;
 7887                    };
 7888                    let invalidation_range = invalidation_range.to_offset(&multibuffer);
 7889                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 7890                    !invalidation_range.contains(&offset_selection.head())
 7891                })
 7892        {
 7893            self.discard_edit_prediction(false, cx);
 7894            return None;
 7895        }
 7896
 7897        self.take_active_edit_prediction(cx);
 7898        let Some(provider) = self.edit_prediction_provider() else {
 7899            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7900            return None;
 7901        };
 7902
 7903        let (buffer, cursor_buffer_position) =
 7904            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7905
 7906        self.edit_prediction_settings =
 7907            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7908
 7909        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 7910
 7911        if self.edit_prediction_indent_conflict {
 7912            let cursor_point = cursor.to_point(&multibuffer);
 7913
 7914            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 7915
 7916            if let Some((_, indent)) = indents.iter().next()
 7917                && indent.len == cursor_point.column
 7918            {
 7919                self.edit_prediction_indent_conflict = false;
 7920            }
 7921        }
 7922
 7923        let edit_prediction = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 7924
 7925        let (completion_id, edits, edit_preview) = match edit_prediction {
 7926            edit_prediction::EditPrediction::Local {
 7927                id,
 7928                edits,
 7929                edit_preview,
 7930            } => (id, edits, edit_preview),
 7931            edit_prediction::EditPrediction::Jump {
 7932                id,
 7933                snapshot,
 7934                target,
 7935            } => {
 7936                self.stale_edit_prediction_in_menu = None;
 7937                self.active_edit_prediction = Some(EditPredictionState {
 7938                    inlay_ids: vec![],
 7939                    completion: EditPrediction::MoveOutside { snapshot, target },
 7940                    completion_id: id,
 7941                    invalidation_range: None,
 7942                });
 7943                cx.notify();
 7944                return Some(());
 7945            }
 7946        };
 7947
 7948        let edits = edits
 7949            .into_iter()
 7950            .flat_map(|(range, new_text)| {
 7951                Some((
 7952                    multibuffer.anchor_range_in_excerpt(excerpt_id, range)?,
 7953                    new_text,
 7954                ))
 7955            })
 7956            .collect::<Vec<_>>();
 7957        if edits.is_empty() {
 7958            return None;
 7959        }
 7960
 7961        let first_edit_start = edits.first().unwrap().0.start;
 7962        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 7963        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 7964
 7965        let last_edit_end = edits.last().unwrap().0.end;
 7966        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 7967        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 7968
 7969        let cursor_row = cursor.to_point(&multibuffer).row;
 7970
 7971        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 7972
 7973        let mut inlay_ids = Vec::new();
 7974        let invalidation_row_range;
 7975        let move_invalidation_row_range = if cursor_row < edit_start_row {
 7976            Some(cursor_row..edit_end_row)
 7977        } else if cursor_row > edit_end_row {
 7978            Some(edit_start_row..cursor_row)
 7979        } else {
 7980            None
 7981        };
 7982        let supports_jump = self
 7983            .edit_prediction_provider
 7984            .as_ref()
 7985            .map(|provider| provider.provider.supports_jump_to_edit())
 7986            .unwrap_or(true);
 7987
 7988        let is_move = supports_jump
 7989            && (move_invalidation_row_range.is_some() || self.edit_predictions_hidden_for_vim_mode);
 7990        let completion = if is_move {
 7991            invalidation_row_range =
 7992                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 7993            let target = first_edit_start;
 7994            EditPrediction::MoveWithin { target, snapshot }
 7995        } else {
 7996            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 7997                && !self.edit_predictions_hidden_for_vim_mode;
 7998
 7999            if show_completions_in_buffer {
 8000                if edits
 8001                    .iter()
 8002                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 8003                {
 8004                    let mut inlays = Vec::new();
 8005                    for (range, new_text) in &edits {
 8006                        let inlay = Inlay::edit_prediction(
 8007                            post_inc(&mut self.next_inlay_id),
 8008                            range.start,
 8009                            new_text.as_ref(),
 8010                        );
 8011                        inlay_ids.push(inlay.id);
 8012                        inlays.push(inlay);
 8013                    }
 8014
 8015                    self.splice_inlays(&[], inlays, cx);
 8016                } else {
 8017                    let background_color = cx.theme().status().deleted_background;
 8018                    self.highlight_text::<EditPredictionHighlight>(
 8019                        edits.iter().map(|(range, _)| range.clone()).collect(),
 8020                        HighlightStyle {
 8021                            background_color: Some(background_color),
 8022                            ..Default::default()
 8023                        },
 8024                        cx,
 8025                    );
 8026                }
 8027            }
 8028
 8029            invalidation_row_range = edit_start_row..edit_end_row;
 8030
 8031            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 8032                if provider.show_tab_accept_marker() {
 8033                    EditDisplayMode::TabAccept
 8034                } else {
 8035                    EditDisplayMode::Inline
 8036                }
 8037            } else {
 8038                EditDisplayMode::DiffPopover
 8039            };
 8040
 8041            EditPrediction::Edit {
 8042                edits,
 8043                edit_preview,
 8044                display_mode,
 8045                snapshot,
 8046            }
 8047        };
 8048
 8049        let invalidation_range = multibuffer
 8050            .anchor_before(Point::new(invalidation_row_range.start, 0))
 8051            ..multibuffer.anchor_after(Point::new(
 8052                invalidation_row_range.end,
 8053                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 8054            ));
 8055
 8056        self.stale_edit_prediction_in_menu = None;
 8057        self.active_edit_prediction = Some(EditPredictionState {
 8058            inlay_ids,
 8059            completion,
 8060            completion_id,
 8061            invalidation_range: Some(invalidation_range),
 8062        });
 8063
 8064        cx.notify();
 8065
 8066        Some(())
 8067    }
 8068
 8069    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn EditPredictionProviderHandle>> {
 8070        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 8071    }
 8072
 8073    fn clear_tasks(&mut self) {
 8074        self.tasks.clear()
 8075    }
 8076
 8077    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 8078        if self.tasks.insert(key, value).is_some() {
 8079            // This case should hopefully be rare, but just in case...
 8080            log::error!(
 8081                "multiple different run targets found on a single line, only the last target will be rendered"
 8082            )
 8083        }
 8084    }
 8085
 8086    /// Get all display points of breakpoints that will be rendered within editor
 8087    ///
 8088    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 8089    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 8090    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 8091    fn active_breakpoints(
 8092        &self,
 8093        range: Range<DisplayRow>,
 8094        window: &mut Window,
 8095        cx: &mut Context<Self>,
 8096    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 8097        let mut breakpoint_display_points = HashMap::default();
 8098
 8099        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 8100            return breakpoint_display_points;
 8101        };
 8102
 8103        let snapshot = self.snapshot(window, cx);
 8104
 8105        let multi_buffer_snapshot = snapshot.buffer_snapshot();
 8106        let Some(project) = self.project() else {
 8107            return breakpoint_display_points;
 8108        };
 8109
 8110        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 8111            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 8112
 8113        for (buffer_snapshot, range, excerpt_id) in
 8114            multi_buffer_snapshot.range_to_buffer_ranges(range)
 8115        {
 8116            let Some(buffer) = project
 8117                .read(cx)
 8118                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 8119            else {
 8120                continue;
 8121            };
 8122            let breakpoints = breakpoint_store.read(cx).breakpoints(
 8123                &buffer,
 8124                Some(
 8125                    buffer_snapshot.anchor_before(range.start)
 8126                        ..buffer_snapshot.anchor_after(range.end),
 8127                ),
 8128                buffer_snapshot,
 8129                cx,
 8130            );
 8131            for (breakpoint, state) in breakpoints {
 8132                let multi_buffer_anchor =
 8133                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 8134                let position = multi_buffer_anchor
 8135                    .to_point(&multi_buffer_snapshot)
 8136                    .to_display_point(&snapshot);
 8137
 8138                breakpoint_display_points.insert(
 8139                    position.row(),
 8140                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 8141                );
 8142            }
 8143        }
 8144
 8145        breakpoint_display_points
 8146    }
 8147
 8148    fn breakpoint_context_menu(
 8149        &self,
 8150        anchor: Anchor,
 8151        window: &mut Window,
 8152        cx: &mut Context<Self>,
 8153    ) -> Entity<ui::ContextMenu> {
 8154        let weak_editor = cx.weak_entity();
 8155        let focus_handle = self.focus_handle(cx);
 8156
 8157        let row = self
 8158            .buffer
 8159            .read(cx)
 8160            .snapshot(cx)
 8161            .summary_for_anchor::<Point>(&anchor)
 8162            .row;
 8163
 8164        let breakpoint = self
 8165            .breakpoint_at_row(row, window, cx)
 8166            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 8167
 8168        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 8169            "Edit Log Breakpoint"
 8170        } else {
 8171            "Set Log Breakpoint"
 8172        };
 8173
 8174        let condition_breakpoint_msg = if breakpoint
 8175            .as_ref()
 8176            .is_some_and(|bp| bp.1.condition.is_some())
 8177        {
 8178            "Edit Condition Breakpoint"
 8179        } else {
 8180            "Set Condition Breakpoint"
 8181        };
 8182
 8183        let hit_condition_breakpoint_msg = if breakpoint
 8184            .as_ref()
 8185            .is_some_and(|bp| bp.1.hit_condition.is_some())
 8186        {
 8187            "Edit Hit Condition Breakpoint"
 8188        } else {
 8189            "Set Hit Condition Breakpoint"
 8190        };
 8191
 8192        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 8193            "Unset Breakpoint"
 8194        } else {
 8195            "Set Breakpoint"
 8196        };
 8197
 8198        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 8199
 8200        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 8201            BreakpointState::Enabled => Some("Disable"),
 8202            BreakpointState::Disabled => Some("Enable"),
 8203        });
 8204
 8205        let (anchor, breakpoint) =
 8206            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 8207
 8208        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 8209            menu.on_blur_subscription(Subscription::new(|| {}))
 8210                .context(focus_handle)
 8211                .when(run_to_cursor, |this| {
 8212                    let weak_editor = weak_editor.clone();
 8213                    this.entry("Run to cursor", None, move |window, cx| {
 8214                        weak_editor
 8215                            .update(cx, |editor, cx| {
 8216                                editor.change_selections(
 8217                                    SelectionEffects::no_scroll(),
 8218                                    window,
 8219                                    cx,
 8220                                    |s| s.select_ranges([Point::new(row, 0)..Point::new(row, 0)]),
 8221                                );
 8222                            })
 8223                            .ok();
 8224
 8225                        window.dispatch_action(Box::new(RunToCursor), cx);
 8226                    })
 8227                    .separator()
 8228                })
 8229                .when_some(toggle_state_msg, |this, msg| {
 8230                    this.entry(msg, None, {
 8231                        let weak_editor = weak_editor.clone();
 8232                        let breakpoint = breakpoint.clone();
 8233                        move |_window, cx| {
 8234                            weak_editor
 8235                                .update(cx, |this, cx| {
 8236                                    this.edit_breakpoint_at_anchor(
 8237                                        anchor,
 8238                                        breakpoint.as_ref().clone(),
 8239                                        BreakpointEditAction::InvertState,
 8240                                        cx,
 8241                                    );
 8242                                })
 8243                                .log_err();
 8244                        }
 8245                    })
 8246                })
 8247                .entry(set_breakpoint_msg, None, {
 8248                    let weak_editor = weak_editor.clone();
 8249                    let breakpoint = breakpoint.clone();
 8250                    move |_window, cx| {
 8251                        weak_editor
 8252                            .update(cx, |this, cx| {
 8253                                this.edit_breakpoint_at_anchor(
 8254                                    anchor,
 8255                                    breakpoint.as_ref().clone(),
 8256                                    BreakpointEditAction::Toggle,
 8257                                    cx,
 8258                                );
 8259                            })
 8260                            .log_err();
 8261                    }
 8262                })
 8263                .entry(log_breakpoint_msg, None, {
 8264                    let breakpoint = breakpoint.clone();
 8265                    let weak_editor = weak_editor.clone();
 8266                    move |window, cx| {
 8267                        weak_editor
 8268                            .update(cx, |this, cx| {
 8269                                this.add_edit_breakpoint_block(
 8270                                    anchor,
 8271                                    breakpoint.as_ref(),
 8272                                    BreakpointPromptEditAction::Log,
 8273                                    window,
 8274                                    cx,
 8275                                );
 8276                            })
 8277                            .log_err();
 8278                    }
 8279                })
 8280                .entry(condition_breakpoint_msg, None, {
 8281                    let breakpoint = breakpoint.clone();
 8282                    let weak_editor = weak_editor.clone();
 8283                    move |window, cx| {
 8284                        weak_editor
 8285                            .update(cx, |this, cx| {
 8286                                this.add_edit_breakpoint_block(
 8287                                    anchor,
 8288                                    breakpoint.as_ref(),
 8289                                    BreakpointPromptEditAction::Condition,
 8290                                    window,
 8291                                    cx,
 8292                                );
 8293                            })
 8294                            .log_err();
 8295                    }
 8296                })
 8297                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 8298                    weak_editor
 8299                        .update(cx, |this, cx| {
 8300                            this.add_edit_breakpoint_block(
 8301                                anchor,
 8302                                breakpoint.as_ref(),
 8303                                BreakpointPromptEditAction::HitCondition,
 8304                                window,
 8305                                cx,
 8306                            );
 8307                        })
 8308                        .log_err();
 8309                })
 8310        })
 8311    }
 8312
 8313    fn render_breakpoint(
 8314        &self,
 8315        position: Anchor,
 8316        row: DisplayRow,
 8317        breakpoint: &Breakpoint,
 8318        state: Option<BreakpointSessionState>,
 8319        cx: &mut Context<Self>,
 8320    ) -> IconButton {
 8321        let is_rejected = state.is_some_and(|s| !s.verified);
 8322        // Is it a breakpoint that shows up when hovering over gutter?
 8323        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 8324            (false, false),
 8325            |PhantomBreakpointIndicator {
 8326                 is_active,
 8327                 display_row,
 8328                 collides_with_existing_breakpoint,
 8329             }| {
 8330                (
 8331                    is_active && display_row == row,
 8332                    collides_with_existing_breakpoint,
 8333                )
 8334            },
 8335        );
 8336
 8337        let (color, icon) = {
 8338            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 8339                (false, false) => ui::IconName::DebugBreakpoint,
 8340                (true, false) => ui::IconName::DebugLogBreakpoint,
 8341                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 8342                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 8343            };
 8344
 8345            let color = if is_phantom {
 8346                Color::Hint
 8347            } else if is_rejected {
 8348                Color::Disabled
 8349            } else {
 8350                Color::Debugger
 8351            };
 8352
 8353            (color, icon)
 8354        };
 8355
 8356        let breakpoint = Arc::from(breakpoint.clone());
 8357
 8358        let alt_as_text = gpui::Keystroke {
 8359            modifiers: Modifiers::secondary_key(),
 8360            ..Default::default()
 8361        };
 8362        let primary_action_text = if breakpoint.is_disabled() {
 8363            "Enable breakpoint"
 8364        } else if is_phantom && !collides_with_existing {
 8365            "Set breakpoint"
 8366        } else {
 8367            "Unset breakpoint"
 8368        };
 8369        let focus_handle = self.focus_handle.clone();
 8370
 8371        let meta = if is_rejected {
 8372            SharedString::from("No executable code is associated with this line.")
 8373        } else if collides_with_existing && !breakpoint.is_disabled() {
 8374            SharedString::from(format!(
 8375                "{alt_as_text}-click to disable,\nright-click for more options."
 8376            ))
 8377        } else {
 8378            SharedString::from("Right-click for more options.")
 8379        };
 8380        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 8381            .icon_size(IconSize::XSmall)
 8382            .size(ui::ButtonSize::None)
 8383            .when(is_rejected, |this| {
 8384                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 8385            })
 8386            .icon_color(color)
 8387            .style(ButtonStyle::Transparent)
 8388            .on_click(cx.listener({
 8389                move |editor, event: &ClickEvent, window, cx| {
 8390                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 8391                        BreakpointEditAction::InvertState
 8392                    } else {
 8393                        BreakpointEditAction::Toggle
 8394                    };
 8395
 8396                    window.focus(&editor.focus_handle(cx));
 8397                    editor.edit_breakpoint_at_anchor(
 8398                        position,
 8399                        breakpoint.as_ref().clone(),
 8400                        edit_action,
 8401                        cx,
 8402                    );
 8403                }
 8404            }))
 8405            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8406                editor.set_breakpoint_context_menu(
 8407                    row,
 8408                    Some(position),
 8409                    event.position(),
 8410                    window,
 8411                    cx,
 8412                );
 8413            }))
 8414            .tooltip(move |_window, cx| {
 8415                Tooltip::with_meta_in(
 8416                    primary_action_text,
 8417                    Some(&ToggleBreakpoint),
 8418                    meta.clone(),
 8419                    &focus_handle,
 8420                    cx,
 8421                )
 8422            })
 8423    }
 8424
 8425    fn build_tasks_context(
 8426        project: &Entity<Project>,
 8427        buffer: &Entity<Buffer>,
 8428        buffer_row: u32,
 8429        tasks: &Arc<RunnableTasks>,
 8430        cx: &mut Context<Self>,
 8431    ) -> Task<Option<task::TaskContext>> {
 8432        let position = Point::new(buffer_row, tasks.column);
 8433        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 8434        let location = Location {
 8435            buffer: buffer.clone(),
 8436            range: range_start..range_start,
 8437        };
 8438        // Fill in the environmental variables from the tree-sitter captures
 8439        let mut captured_task_variables = TaskVariables::default();
 8440        for (capture_name, value) in tasks.extra_variables.clone() {
 8441            captured_task_variables.insert(
 8442                task::VariableName::Custom(capture_name.into()),
 8443                value.clone(),
 8444            );
 8445        }
 8446        project.update(cx, |project, cx| {
 8447            project.task_store().update(cx, |task_store, cx| {
 8448                task_store.task_context_for_location(captured_task_variables, location, cx)
 8449            })
 8450        })
 8451    }
 8452
 8453    pub fn spawn_nearest_task(
 8454        &mut self,
 8455        action: &SpawnNearestTask,
 8456        window: &mut Window,
 8457        cx: &mut Context<Self>,
 8458    ) {
 8459        let Some((workspace, _)) = self.workspace.clone() else {
 8460            return;
 8461        };
 8462        let Some(project) = self.project.clone() else {
 8463            return;
 8464        };
 8465
 8466        // Try to find a closest, enclosing node using tree-sitter that has a task
 8467        let Some((buffer, buffer_row, tasks)) = self
 8468            .find_enclosing_node_task(cx)
 8469            // Or find the task that's closest in row-distance.
 8470            .or_else(|| self.find_closest_task(cx))
 8471        else {
 8472            return;
 8473        };
 8474
 8475        let reveal_strategy = action.reveal;
 8476        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 8477        cx.spawn_in(window, async move |_, cx| {
 8478            let context = task_context.await?;
 8479            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 8480
 8481            let resolved = &mut resolved_task.resolved;
 8482            resolved.reveal = reveal_strategy;
 8483
 8484            workspace
 8485                .update_in(cx, |workspace, window, cx| {
 8486                    workspace.schedule_resolved_task(
 8487                        task_source_kind,
 8488                        resolved_task,
 8489                        false,
 8490                        window,
 8491                        cx,
 8492                    );
 8493                })
 8494                .ok()
 8495        })
 8496        .detach();
 8497    }
 8498
 8499    fn find_closest_task(
 8500        &mut self,
 8501        cx: &mut Context<Self>,
 8502    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8503        let cursor_row = self
 8504            .selections
 8505            .newest_adjusted(&self.display_snapshot(cx))
 8506            .head()
 8507            .row;
 8508
 8509        let ((buffer_id, row), tasks) = self
 8510            .tasks
 8511            .iter()
 8512            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 8513
 8514        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 8515        let tasks = Arc::new(tasks.to_owned());
 8516        Some((buffer, *row, tasks))
 8517    }
 8518
 8519    fn find_enclosing_node_task(
 8520        &mut self,
 8521        cx: &mut Context<Self>,
 8522    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8523        let snapshot = self.buffer.read(cx).snapshot(cx);
 8524        let offset = self
 8525            .selections
 8526            .newest::<usize>(&self.display_snapshot(cx))
 8527            .head();
 8528        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 8529        let buffer_id = excerpt.buffer().remote_id();
 8530
 8531        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 8532        let mut cursor = layer.node().walk();
 8533
 8534        while cursor.goto_first_child_for_byte(offset).is_some() {
 8535            if cursor.node().end_byte() == offset {
 8536                cursor.goto_next_sibling();
 8537            }
 8538        }
 8539
 8540        // Ascend to the smallest ancestor that contains the range and has a task.
 8541        loop {
 8542            let node = cursor.node();
 8543            let node_range = node.byte_range();
 8544            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 8545
 8546            // Check if this node contains our offset
 8547            if node_range.start <= offset && node_range.end >= offset {
 8548                // If it contains offset, check for task
 8549                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 8550                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 8551                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 8552                }
 8553            }
 8554
 8555            if !cursor.goto_parent() {
 8556                break;
 8557            }
 8558        }
 8559        None
 8560    }
 8561
 8562    fn render_run_indicator(
 8563        &self,
 8564        _style: &EditorStyle,
 8565        is_active: bool,
 8566        row: DisplayRow,
 8567        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 8568        cx: &mut Context<Self>,
 8569    ) -> IconButton {
 8570        let color = Color::Muted;
 8571        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 8572
 8573        IconButton::new(
 8574            ("run_indicator", row.0 as usize),
 8575            ui::IconName::PlayOutlined,
 8576        )
 8577        .shape(ui::IconButtonShape::Square)
 8578        .icon_size(IconSize::XSmall)
 8579        .icon_color(color)
 8580        .toggle_state(is_active)
 8581        .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 8582            let quick_launch = match e {
 8583                ClickEvent::Keyboard(_) => true,
 8584                ClickEvent::Mouse(e) => e.down.button == MouseButton::Left,
 8585            };
 8586
 8587            window.focus(&editor.focus_handle(cx));
 8588            editor.toggle_code_actions(
 8589                &ToggleCodeActions {
 8590                    deployed_from: Some(CodeActionSource::RunMenu(row)),
 8591                    quick_launch,
 8592                },
 8593                window,
 8594                cx,
 8595            );
 8596        }))
 8597        .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8598            editor.set_breakpoint_context_menu(row, position, event.position(), window, cx);
 8599        }))
 8600    }
 8601
 8602    pub fn context_menu_visible(&self) -> bool {
 8603        !self.edit_prediction_preview_is_active()
 8604            && self
 8605                .context_menu
 8606                .borrow()
 8607                .as_ref()
 8608                .is_some_and(|menu| menu.visible())
 8609    }
 8610
 8611    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 8612        self.context_menu
 8613            .borrow()
 8614            .as_ref()
 8615            .map(|menu| menu.origin())
 8616    }
 8617
 8618    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 8619        self.context_menu_options = Some(options);
 8620    }
 8621
 8622    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = px(24.);
 8623    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = px(2.);
 8624
 8625    fn render_edit_prediction_popover(
 8626        &mut self,
 8627        text_bounds: &Bounds<Pixels>,
 8628        content_origin: gpui::Point<Pixels>,
 8629        right_margin: Pixels,
 8630        editor_snapshot: &EditorSnapshot,
 8631        visible_row_range: Range<DisplayRow>,
 8632        scroll_top: ScrollOffset,
 8633        scroll_bottom: ScrollOffset,
 8634        line_layouts: &[LineWithInvisibles],
 8635        line_height: Pixels,
 8636        scroll_position: gpui::Point<ScrollOffset>,
 8637        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8638        newest_selection_head: Option<DisplayPoint>,
 8639        editor_width: Pixels,
 8640        style: &EditorStyle,
 8641        window: &mut Window,
 8642        cx: &mut App,
 8643    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8644        if self.mode().is_minimap() {
 8645            return None;
 8646        }
 8647        let active_edit_prediction = self.active_edit_prediction.as_ref()?;
 8648
 8649        if self.edit_prediction_visible_in_cursor_popover(true) {
 8650            return None;
 8651        }
 8652
 8653        match &active_edit_prediction.completion {
 8654            EditPrediction::MoveWithin { target, .. } => {
 8655                let target_display_point = target.to_display_point(editor_snapshot);
 8656
 8657                if self.edit_prediction_requires_modifier() {
 8658                    if !self.edit_prediction_preview_is_active() {
 8659                        return None;
 8660                    }
 8661
 8662                    self.render_edit_prediction_modifier_jump_popover(
 8663                        text_bounds,
 8664                        content_origin,
 8665                        visible_row_range,
 8666                        line_layouts,
 8667                        line_height,
 8668                        scroll_pixel_position,
 8669                        newest_selection_head,
 8670                        target_display_point,
 8671                        window,
 8672                        cx,
 8673                    )
 8674                } else {
 8675                    self.render_edit_prediction_eager_jump_popover(
 8676                        text_bounds,
 8677                        content_origin,
 8678                        editor_snapshot,
 8679                        visible_row_range,
 8680                        scroll_top,
 8681                        scroll_bottom,
 8682                        line_height,
 8683                        scroll_pixel_position,
 8684                        target_display_point,
 8685                        editor_width,
 8686                        window,
 8687                        cx,
 8688                    )
 8689                }
 8690            }
 8691            EditPrediction::Edit {
 8692                display_mode: EditDisplayMode::Inline,
 8693                ..
 8694            } => None,
 8695            EditPrediction::Edit {
 8696                display_mode: EditDisplayMode::TabAccept,
 8697                edits,
 8698                ..
 8699            } => {
 8700                let range = &edits.first()?.0;
 8701                let target_display_point = range.end.to_display_point(editor_snapshot);
 8702
 8703                self.render_edit_prediction_end_of_line_popover(
 8704                    "Accept",
 8705                    editor_snapshot,
 8706                    visible_row_range,
 8707                    target_display_point,
 8708                    line_height,
 8709                    scroll_pixel_position,
 8710                    content_origin,
 8711                    editor_width,
 8712                    window,
 8713                    cx,
 8714                )
 8715            }
 8716            EditPrediction::Edit {
 8717                edits,
 8718                edit_preview,
 8719                display_mode: EditDisplayMode::DiffPopover,
 8720                snapshot,
 8721            } => self.render_edit_prediction_diff_popover(
 8722                text_bounds,
 8723                content_origin,
 8724                right_margin,
 8725                editor_snapshot,
 8726                visible_row_range,
 8727                line_layouts,
 8728                line_height,
 8729                scroll_position,
 8730                scroll_pixel_position,
 8731                newest_selection_head,
 8732                editor_width,
 8733                style,
 8734                edits,
 8735                edit_preview,
 8736                snapshot,
 8737                window,
 8738                cx,
 8739            ),
 8740            EditPrediction::MoveOutside { snapshot, .. } => {
 8741                let file_name = snapshot
 8742                    .file()
 8743                    .map(|file| file.file_name(cx))
 8744                    .unwrap_or("untitled");
 8745                let mut element = self
 8746                    .render_edit_prediction_line_popover(
 8747                        format!("Jump to {file_name}"),
 8748                        Some(IconName::ZedPredict),
 8749                        window,
 8750                        cx,
 8751                    )
 8752                    .into_any();
 8753
 8754                let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8755                let origin_x = text_bounds.size.width / 2. - size.width / 2.;
 8756                let origin_y = text_bounds.size.height - size.height - px(30.);
 8757                let origin = text_bounds.origin + gpui::Point::new(origin_x, origin_y);
 8758                element.prepaint_at(origin, window, cx);
 8759
 8760                Some((element, origin))
 8761            }
 8762        }
 8763    }
 8764
 8765    fn render_edit_prediction_modifier_jump_popover(
 8766        &mut self,
 8767        text_bounds: &Bounds<Pixels>,
 8768        content_origin: gpui::Point<Pixels>,
 8769        visible_row_range: Range<DisplayRow>,
 8770        line_layouts: &[LineWithInvisibles],
 8771        line_height: Pixels,
 8772        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8773        newest_selection_head: Option<DisplayPoint>,
 8774        target_display_point: DisplayPoint,
 8775        window: &mut Window,
 8776        cx: &mut App,
 8777    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8778        let scrolled_content_origin =
 8779            content_origin - gpui::Point::new(scroll_pixel_position.x.into(), Pixels::ZERO);
 8780
 8781        const SCROLL_PADDING_Y: Pixels = px(12.);
 8782
 8783        if target_display_point.row() < visible_row_range.start {
 8784            return self.render_edit_prediction_scroll_popover(
 8785                |_| SCROLL_PADDING_Y,
 8786                IconName::ArrowUp,
 8787                visible_row_range,
 8788                line_layouts,
 8789                newest_selection_head,
 8790                scrolled_content_origin,
 8791                window,
 8792                cx,
 8793            );
 8794        } else if target_display_point.row() >= visible_row_range.end {
 8795            return self.render_edit_prediction_scroll_popover(
 8796                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 8797                IconName::ArrowDown,
 8798                visible_row_range,
 8799                line_layouts,
 8800                newest_selection_head,
 8801                scrolled_content_origin,
 8802                window,
 8803                cx,
 8804            );
 8805        }
 8806
 8807        const POLE_WIDTH: Pixels = px(2.);
 8808
 8809        let line_layout =
 8810            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 8811        let target_column = target_display_point.column() as usize;
 8812
 8813        let target_x = line_layout.x_for_index(target_column);
 8814        let target_y = (target_display_point.row().as_f64() * f64::from(line_height))
 8815            - scroll_pixel_position.y;
 8816
 8817        let flag_on_right = target_x < text_bounds.size.width / 2.;
 8818
 8819        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 8820        border_color.l += 0.001;
 8821
 8822        let mut element = v_flex()
 8823            .items_end()
 8824            .when(flag_on_right, |el| el.items_start())
 8825            .child(if flag_on_right {
 8826                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 8827                    .rounded_bl(px(0.))
 8828                    .rounded_tl(px(0.))
 8829                    .border_l_2()
 8830                    .border_color(border_color)
 8831            } else {
 8832                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 8833                    .rounded_br(px(0.))
 8834                    .rounded_tr(px(0.))
 8835                    .border_r_2()
 8836                    .border_color(border_color)
 8837            })
 8838            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 8839            .into_any();
 8840
 8841        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8842
 8843        let mut origin = scrolled_content_origin + point(target_x, target_y.into())
 8844            - point(
 8845                if flag_on_right {
 8846                    POLE_WIDTH
 8847                } else {
 8848                    size.width - POLE_WIDTH
 8849                },
 8850                size.height - line_height,
 8851            );
 8852
 8853        origin.x = origin.x.max(content_origin.x);
 8854
 8855        element.prepaint_at(origin, window, cx);
 8856
 8857        Some((element, origin))
 8858    }
 8859
 8860    fn render_edit_prediction_scroll_popover(
 8861        &mut self,
 8862        to_y: impl Fn(Size<Pixels>) -> Pixels,
 8863        scroll_icon: IconName,
 8864        visible_row_range: Range<DisplayRow>,
 8865        line_layouts: &[LineWithInvisibles],
 8866        newest_selection_head: Option<DisplayPoint>,
 8867        scrolled_content_origin: gpui::Point<Pixels>,
 8868        window: &mut Window,
 8869        cx: &mut App,
 8870    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8871        let mut element = self
 8872            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)
 8873            .into_any();
 8874
 8875        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8876
 8877        let cursor = newest_selection_head?;
 8878        let cursor_row_layout =
 8879            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 8880        let cursor_column = cursor.column() as usize;
 8881
 8882        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 8883
 8884        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 8885
 8886        element.prepaint_at(origin, window, cx);
 8887        Some((element, origin))
 8888    }
 8889
 8890    fn render_edit_prediction_eager_jump_popover(
 8891        &mut self,
 8892        text_bounds: &Bounds<Pixels>,
 8893        content_origin: gpui::Point<Pixels>,
 8894        editor_snapshot: &EditorSnapshot,
 8895        visible_row_range: Range<DisplayRow>,
 8896        scroll_top: ScrollOffset,
 8897        scroll_bottom: ScrollOffset,
 8898        line_height: Pixels,
 8899        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8900        target_display_point: DisplayPoint,
 8901        editor_width: Pixels,
 8902        window: &mut Window,
 8903        cx: &mut App,
 8904    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8905        if target_display_point.row().as_f64() < scroll_top {
 8906            let mut element = self
 8907                .render_edit_prediction_line_popover(
 8908                    "Jump to Edit",
 8909                    Some(IconName::ArrowUp),
 8910                    window,
 8911                    cx,
 8912                )
 8913                .into_any();
 8914
 8915            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8916            let offset = point(
 8917                (text_bounds.size.width - size.width) / 2.,
 8918                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8919            );
 8920
 8921            let origin = text_bounds.origin + offset;
 8922            element.prepaint_at(origin, window, cx);
 8923            Some((element, origin))
 8924        } else if (target_display_point.row().as_f64() + 1.) > scroll_bottom {
 8925            let mut element = self
 8926                .render_edit_prediction_line_popover(
 8927                    "Jump to Edit",
 8928                    Some(IconName::ArrowDown),
 8929                    window,
 8930                    cx,
 8931                )
 8932                .into_any();
 8933
 8934            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8935            let offset = point(
 8936                (text_bounds.size.width - size.width) / 2.,
 8937                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8938            );
 8939
 8940            let origin = text_bounds.origin + offset;
 8941            element.prepaint_at(origin, window, cx);
 8942            Some((element, origin))
 8943        } else {
 8944            self.render_edit_prediction_end_of_line_popover(
 8945                "Jump to Edit",
 8946                editor_snapshot,
 8947                visible_row_range,
 8948                target_display_point,
 8949                line_height,
 8950                scroll_pixel_position,
 8951                content_origin,
 8952                editor_width,
 8953                window,
 8954                cx,
 8955            )
 8956        }
 8957    }
 8958
 8959    fn render_edit_prediction_end_of_line_popover(
 8960        self: &mut Editor,
 8961        label: &'static str,
 8962        editor_snapshot: &EditorSnapshot,
 8963        visible_row_range: Range<DisplayRow>,
 8964        target_display_point: DisplayPoint,
 8965        line_height: Pixels,
 8966        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8967        content_origin: gpui::Point<Pixels>,
 8968        editor_width: Pixels,
 8969        window: &mut Window,
 8970        cx: &mut App,
 8971    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8972        let target_line_end = DisplayPoint::new(
 8973            target_display_point.row(),
 8974            editor_snapshot.line_len(target_display_point.row()),
 8975        );
 8976
 8977        let mut element = self
 8978            .render_edit_prediction_line_popover(label, None, window, cx)
 8979            .into_any();
 8980
 8981        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8982
 8983        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 8984
 8985        let start_point = content_origin - point(scroll_pixel_position.x.into(), Pixels::ZERO);
 8986        let mut origin = start_point
 8987            + line_origin
 8988            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 8989        origin.x = origin.x.max(content_origin.x);
 8990
 8991        let max_x = content_origin.x + editor_width - size.width;
 8992
 8993        if origin.x > max_x {
 8994            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 8995
 8996            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 8997                origin.y += offset;
 8998                IconName::ArrowUp
 8999            } else {
 9000                origin.y -= offset;
 9001                IconName::ArrowDown
 9002            };
 9003
 9004            element = self
 9005                .render_edit_prediction_line_popover(label, Some(icon), window, cx)
 9006                .into_any();
 9007
 9008            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9009
 9010            origin.x = content_origin.x + editor_width - size.width - px(2.);
 9011        }
 9012
 9013        element.prepaint_at(origin, window, cx);
 9014        Some((element, origin))
 9015    }
 9016
 9017    fn render_edit_prediction_diff_popover(
 9018        self: &Editor,
 9019        text_bounds: &Bounds<Pixels>,
 9020        content_origin: gpui::Point<Pixels>,
 9021        right_margin: Pixels,
 9022        editor_snapshot: &EditorSnapshot,
 9023        visible_row_range: Range<DisplayRow>,
 9024        line_layouts: &[LineWithInvisibles],
 9025        line_height: Pixels,
 9026        scroll_position: gpui::Point<ScrollOffset>,
 9027        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9028        newest_selection_head: Option<DisplayPoint>,
 9029        editor_width: Pixels,
 9030        style: &EditorStyle,
 9031        edits: &Vec<(Range<Anchor>, Arc<str>)>,
 9032        edit_preview: &Option<language::EditPreview>,
 9033        snapshot: &language::BufferSnapshot,
 9034        window: &mut Window,
 9035        cx: &mut App,
 9036    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9037        let edit_start = edits
 9038            .first()
 9039            .unwrap()
 9040            .0
 9041            .start
 9042            .to_display_point(editor_snapshot);
 9043        let edit_end = edits
 9044            .last()
 9045            .unwrap()
 9046            .0
 9047            .end
 9048            .to_display_point(editor_snapshot);
 9049
 9050        let is_visible = visible_row_range.contains(&edit_start.row())
 9051            || visible_row_range.contains(&edit_end.row());
 9052        if !is_visible {
 9053            return None;
 9054        }
 9055
 9056        let highlighted_edits = if let Some(edit_preview) = edit_preview.as_ref() {
 9057            crate::edit_prediction_edit_text(snapshot, edits, edit_preview, false, cx)
 9058        } else {
 9059            // Fallback for providers without edit_preview
 9060            crate::edit_prediction_fallback_text(edits, cx)
 9061        };
 9062
 9063        let styled_text = highlighted_edits.to_styled_text(&style.text);
 9064        let line_count = highlighted_edits.text.lines().count();
 9065
 9066        const BORDER_WIDTH: Pixels = px(1.);
 9067
 9068        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9069        let has_keybind = keybind.is_some();
 9070
 9071        let mut element = h_flex()
 9072            .items_start()
 9073            .child(
 9074                h_flex()
 9075                    .bg(cx.theme().colors().editor_background)
 9076                    .border(BORDER_WIDTH)
 9077                    .shadow_xs()
 9078                    .border_color(cx.theme().colors().border)
 9079                    .rounded_l_lg()
 9080                    .when(line_count > 1, |el| el.rounded_br_lg())
 9081                    .pr_1()
 9082                    .child(styled_text),
 9083            )
 9084            .child(
 9085                h_flex()
 9086                    .h(line_height + BORDER_WIDTH * 2.)
 9087                    .px_1p5()
 9088                    .gap_1()
 9089                    // Workaround: For some reason, there's a gap if we don't do this
 9090                    .ml(-BORDER_WIDTH)
 9091                    .shadow(vec![gpui::BoxShadow {
 9092                        color: gpui::black().opacity(0.05),
 9093                        offset: point(px(1.), px(1.)),
 9094                        blur_radius: px(2.),
 9095                        spread_radius: px(0.),
 9096                    }])
 9097                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 9098                    .border(BORDER_WIDTH)
 9099                    .border_color(cx.theme().colors().border)
 9100                    .rounded_r_lg()
 9101                    .id("edit_prediction_diff_popover_keybind")
 9102                    .when(!has_keybind, |el| {
 9103                        let status_colors = cx.theme().status();
 9104
 9105                        el.bg(status_colors.error_background)
 9106                            .border_color(status_colors.error.opacity(0.6))
 9107                            .child(Icon::new(IconName::Info).color(Color::Error))
 9108                            .cursor_default()
 9109                            .hoverable_tooltip(move |_window, cx| {
 9110                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9111                            })
 9112                    })
 9113                    .children(keybind),
 9114            )
 9115            .into_any();
 9116
 9117        let longest_row =
 9118            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 9119        let longest_line_width = if visible_row_range.contains(&longest_row) {
 9120            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 9121        } else {
 9122            layout_line(
 9123                longest_row,
 9124                editor_snapshot,
 9125                style,
 9126                editor_width,
 9127                |_| false,
 9128                window,
 9129                cx,
 9130            )
 9131            .width
 9132        };
 9133
 9134        let viewport_bounds =
 9135            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 9136                right: -right_margin,
 9137                ..Default::default()
 9138            });
 9139
 9140        let x_after_longest = Pixels::from(
 9141            ScrollPixelOffset::from(
 9142                text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X,
 9143            ) - scroll_pixel_position.x,
 9144        );
 9145
 9146        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9147
 9148        // Fully visible if it can be displayed within the window (allow overlapping other
 9149        // panes). However, this is only allowed if the popover starts within text_bounds.
 9150        let can_position_to_the_right = x_after_longest < text_bounds.right()
 9151            && x_after_longest + element_bounds.width < viewport_bounds.right();
 9152
 9153        let mut origin = if can_position_to_the_right {
 9154            point(
 9155                x_after_longest,
 9156                text_bounds.origin.y
 9157                    + Pixels::from(
 9158                        edit_start.row().as_f64() * ScrollPixelOffset::from(line_height)
 9159                            - scroll_pixel_position.y,
 9160                    ),
 9161            )
 9162        } else {
 9163            let cursor_row = newest_selection_head.map(|head| head.row());
 9164            let above_edit = edit_start
 9165                .row()
 9166                .0
 9167                .checked_sub(line_count as u32)
 9168                .map(DisplayRow);
 9169            let below_edit = Some(edit_end.row() + 1);
 9170            let above_cursor =
 9171                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 9172            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 9173
 9174            // Place the edit popover adjacent to the edit if there is a location
 9175            // available that is onscreen and does not obscure the cursor. Otherwise,
 9176            // place it adjacent to the cursor.
 9177            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 9178                .into_iter()
 9179                .flatten()
 9180                .find(|&start_row| {
 9181                    let end_row = start_row + line_count as u32;
 9182                    visible_row_range.contains(&start_row)
 9183                        && visible_row_range.contains(&end_row)
 9184                        && cursor_row
 9185                            .is_none_or(|cursor_row| !((start_row..end_row).contains(&cursor_row)))
 9186                })?;
 9187
 9188            content_origin
 9189                + point(
 9190                    Pixels::from(-scroll_pixel_position.x),
 9191                    Pixels::from(
 9192                        (row_target.as_f64() - scroll_position.y) * f64::from(line_height),
 9193                    ),
 9194                )
 9195        };
 9196
 9197        origin.x -= BORDER_WIDTH;
 9198
 9199        window.defer_draw(element, origin, 1);
 9200
 9201        // Do not return an element, since it will already be drawn due to defer_draw.
 9202        None
 9203    }
 9204
 9205    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 9206        px(30.)
 9207    }
 9208
 9209    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 9210        if self.read_only(cx) {
 9211            cx.theme().players().read_only()
 9212        } else {
 9213            self.style.as_ref().unwrap().local_player
 9214        }
 9215    }
 9216
 9217    fn render_edit_prediction_accept_keybind(
 9218        &self,
 9219        window: &mut Window,
 9220        cx: &mut App,
 9221    ) -> Option<AnyElement> {
 9222        let accept_binding = self.accept_edit_prediction_keybind(false, window, cx);
 9223        let accept_keystroke = accept_binding.keystroke()?;
 9224
 9225        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9226
 9227        let modifiers_color = if *accept_keystroke.modifiers() == window.modifiers() {
 9228            Color::Accent
 9229        } else {
 9230            Color::Muted
 9231        };
 9232
 9233        h_flex()
 9234            .px_0p5()
 9235            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 9236            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9237            .text_size(TextSize::XSmall.rems(cx))
 9238            .child(h_flex().children(ui::render_modifiers(
 9239                accept_keystroke.modifiers(),
 9240                PlatformStyle::platform(),
 9241                Some(modifiers_color),
 9242                Some(IconSize::XSmall.rems().into()),
 9243                true,
 9244            )))
 9245            .when(is_platform_style_mac, |parent| {
 9246                parent.child(accept_keystroke.key().to_string())
 9247            })
 9248            .when(!is_platform_style_mac, |parent| {
 9249                parent.child(
 9250                    Key::new(
 9251                        util::capitalize(accept_keystroke.key()),
 9252                        Some(Color::Default),
 9253                    )
 9254                    .size(Some(IconSize::XSmall.rems().into())),
 9255                )
 9256            })
 9257            .into_any()
 9258            .into()
 9259    }
 9260
 9261    fn render_edit_prediction_line_popover(
 9262        &self,
 9263        label: impl Into<SharedString>,
 9264        icon: Option<IconName>,
 9265        window: &mut Window,
 9266        cx: &mut App,
 9267    ) -> Stateful<Div> {
 9268        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 9269
 9270        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9271        let has_keybind = keybind.is_some();
 9272
 9273        h_flex()
 9274            .id("ep-line-popover")
 9275            .py_0p5()
 9276            .pl_1()
 9277            .pr(padding_right)
 9278            .gap_1()
 9279            .rounded_md()
 9280            .border_1()
 9281            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9282            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9283            .shadow_xs()
 9284            .when(!has_keybind, |el| {
 9285                let status_colors = cx.theme().status();
 9286
 9287                el.bg(status_colors.error_background)
 9288                    .border_color(status_colors.error.opacity(0.6))
 9289                    .pl_2()
 9290                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9291                    .cursor_default()
 9292                    .hoverable_tooltip(move |_window, cx| {
 9293                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9294                    })
 9295            })
 9296            .children(keybind)
 9297            .child(
 9298                Label::new(label)
 9299                    .size(LabelSize::Small)
 9300                    .when(!has_keybind, |el| {
 9301                        el.color(cx.theme().status().error.into()).strikethrough()
 9302                    }),
 9303            )
 9304            .when(!has_keybind, |el| {
 9305                el.child(
 9306                    h_flex().ml_1().child(
 9307                        Icon::new(IconName::Info)
 9308                            .size(IconSize::Small)
 9309                            .color(cx.theme().status().error.into()),
 9310                    ),
 9311                )
 9312            })
 9313            .when_some(icon, |element, icon| {
 9314                element.child(
 9315                    div()
 9316                        .mt(px(1.5))
 9317                        .child(Icon::new(icon).size(IconSize::Small)),
 9318                )
 9319            })
 9320    }
 9321
 9322    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 9323        let accent_color = cx.theme().colors().text_accent;
 9324        let editor_bg_color = cx.theme().colors().editor_background;
 9325        editor_bg_color.blend(accent_color.opacity(0.1))
 9326    }
 9327
 9328    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 9329        let accent_color = cx.theme().colors().text_accent;
 9330        let editor_bg_color = cx.theme().colors().editor_background;
 9331        editor_bg_color.blend(accent_color.opacity(0.6))
 9332    }
 9333    fn get_prediction_provider_icon_name(
 9334        provider: &Option<RegisteredEditPredictionProvider>,
 9335    ) -> IconName {
 9336        match provider {
 9337            Some(provider) => match provider.provider.name() {
 9338                "copilot" => IconName::Copilot,
 9339                "supermaven" => IconName::Supermaven,
 9340                _ => IconName::ZedPredict,
 9341            },
 9342            None => IconName::ZedPredict,
 9343        }
 9344    }
 9345
 9346    fn render_edit_prediction_cursor_popover(
 9347        &self,
 9348        min_width: Pixels,
 9349        max_width: Pixels,
 9350        cursor_point: Point,
 9351        style: &EditorStyle,
 9352        accept_keystroke: Option<&gpui::KeybindingKeystroke>,
 9353        _window: &Window,
 9354        cx: &mut Context<Editor>,
 9355    ) -> Option<AnyElement> {
 9356        let provider = self.edit_prediction_provider.as_ref()?;
 9357        let provider_icon = Self::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9358
 9359        let is_refreshing = provider.provider.is_refreshing(cx);
 9360
 9361        fn pending_completion_container(icon: IconName) -> Div {
 9362            h_flex().h_full().flex_1().gap_2().child(Icon::new(icon))
 9363        }
 9364
 9365        let completion = match &self.active_edit_prediction {
 9366            Some(prediction) => {
 9367                if !self.has_visible_completions_menu() {
 9368                    const RADIUS: Pixels = px(6.);
 9369                    const BORDER_WIDTH: Pixels = px(1.);
 9370
 9371                    return Some(
 9372                        h_flex()
 9373                            .elevation_2(cx)
 9374                            .border(BORDER_WIDTH)
 9375                            .border_color(cx.theme().colors().border)
 9376                            .when(accept_keystroke.is_none(), |el| {
 9377                                el.border_color(cx.theme().status().error)
 9378                            })
 9379                            .rounded(RADIUS)
 9380                            .rounded_tl(px(0.))
 9381                            .overflow_hidden()
 9382                            .child(div().px_1p5().child(match &prediction.completion {
 9383                                EditPrediction::MoveWithin { target, snapshot } => {
 9384                                    use text::ToPoint as _;
 9385                                    if target.text_anchor.to_point(snapshot).row > cursor_point.row
 9386                                    {
 9387                                        Icon::new(IconName::ZedPredictDown)
 9388                                    } else {
 9389                                        Icon::new(IconName::ZedPredictUp)
 9390                                    }
 9391                                }
 9392                                EditPrediction::MoveOutside { .. } => {
 9393                                    // TODO [zeta2] custom icon for external jump?
 9394                                    Icon::new(provider_icon)
 9395                                }
 9396                                EditPrediction::Edit { .. } => Icon::new(provider_icon),
 9397                            }))
 9398                            .child(
 9399                                h_flex()
 9400                                    .gap_1()
 9401                                    .py_1()
 9402                                    .px_2()
 9403                                    .rounded_r(RADIUS - BORDER_WIDTH)
 9404                                    .border_l_1()
 9405                                    .border_color(cx.theme().colors().border)
 9406                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9407                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 9408                                        el.child(
 9409                                            Label::new("Hold")
 9410                                                .size(LabelSize::Small)
 9411                                                .when(accept_keystroke.is_none(), |el| {
 9412                                                    el.strikethrough()
 9413                                                })
 9414                                                .line_height_style(LineHeightStyle::UiLabel),
 9415                                        )
 9416                                    })
 9417                                    .id("edit_prediction_cursor_popover_keybind")
 9418                                    .when(accept_keystroke.is_none(), |el| {
 9419                                        let status_colors = cx.theme().status();
 9420
 9421                                        el.bg(status_colors.error_background)
 9422                                            .border_color(status_colors.error.opacity(0.6))
 9423                                            .child(Icon::new(IconName::Info).color(Color::Error))
 9424                                            .cursor_default()
 9425                                            .hoverable_tooltip(move |_window, cx| {
 9426                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 9427                                                    .into()
 9428                                            })
 9429                                    })
 9430                                    .when_some(
 9431                                        accept_keystroke.as_ref(),
 9432                                        |el, accept_keystroke| {
 9433                                            el.child(h_flex().children(ui::render_modifiers(
 9434                                                accept_keystroke.modifiers(),
 9435                                                PlatformStyle::platform(),
 9436                                                Some(Color::Default),
 9437                                                Some(IconSize::XSmall.rems().into()),
 9438                                                false,
 9439                                            )))
 9440                                        },
 9441                                    ),
 9442                            )
 9443                            .into_any(),
 9444                    );
 9445                }
 9446
 9447                self.render_edit_prediction_cursor_popover_preview(
 9448                    prediction,
 9449                    cursor_point,
 9450                    style,
 9451                    cx,
 9452                )?
 9453            }
 9454
 9455            None if is_refreshing => match &self.stale_edit_prediction_in_menu {
 9456                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 9457                    stale_completion,
 9458                    cursor_point,
 9459                    style,
 9460                    cx,
 9461                )?,
 9462
 9463                None => pending_completion_container(provider_icon)
 9464                    .child(Label::new("...").size(LabelSize::Small)),
 9465            },
 9466
 9467            None => pending_completion_container(provider_icon)
 9468                .child(Label::new("...").size(LabelSize::Small)),
 9469        };
 9470
 9471        let completion = if is_refreshing || self.active_edit_prediction.is_none() {
 9472            completion
 9473                .with_animation(
 9474                    "loading-completion",
 9475                    Animation::new(Duration::from_secs(2))
 9476                        .repeat()
 9477                        .with_easing(pulsating_between(0.4, 0.8)),
 9478                    |label, delta| label.opacity(delta),
 9479                )
 9480                .into_any_element()
 9481        } else {
 9482            completion.into_any_element()
 9483        };
 9484
 9485        let has_completion = self.active_edit_prediction.is_some();
 9486
 9487        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9488        Some(
 9489            h_flex()
 9490                .min_w(min_width)
 9491                .max_w(max_width)
 9492                .flex_1()
 9493                .elevation_2(cx)
 9494                .border_color(cx.theme().colors().border)
 9495                .child(
 9496                    div()
 9497                        .flex_1()
 9498                        .py_1()
 9499                        .px_2()
 9500                        .overflow_hidden()
 9501                        .child(completion),
 9502                )
 9503                .when_some(accept_keystroke, |el, accept_keystroke| {
 9504                    if !accept_keystroke.modifiers().modified() {
 9505                        return el;
 9506                    }
 9507
 9508                    el.child(
 9509                        h_flex()
 9510                            .h_full()
 9511                            .border_l_1()
 9512                            .rounded_r_lg()
 9513                            .border_color(cx.theme().colors().border)
 9514                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9515                            .gap_1()
 9516                            .py_1()
 9517                            .px_2()
 9518                            .child(
 9519                                h_flex()
 9520                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9521                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 9522                                    .child(h_flex().children(ui::render_modifiers(
 9523                                        accept_keystroke.modifiers(),
 9524                                        PlatformStyle::platform(),
 9525                                        Some(if !has_completion {
 9526                                            Color::Muted
 9527                                        } else {
 9528                                            Color::Default
 9529                                        }),
 9530                                        None,
 9531                                        false,
 9532                                    ))),
 9533                            )
 9534                            .child(Label::new("Preview").into_any_element())
 9535                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 9536                    )
 9537                })
 9538                .into_any(),
 9539        )
 9540    }
 9541
 9542    fn render_edit_prediction_cursor_popover_preview(
 9543        &self,
 9544        completion: &EditPredictionState,
 9545        cursor_point: Point,
 9546        style: &EditorStyle,
 9547        cx: &mut Context<Editor>,
 9548    ) -> Option<Div> {
 9549        use text::ToPoint as _;
 9550
 9551        fn render_relative_row_jump(
 9552            prefix: impl Into<String>,
 9553            current_row: u32,
 9554            target_row: u32,
 9555        ) -> Div {
 9556            let (row_diff, arrow) = if target_row < current_row {
 9557                (current_row - target_row, IconName::ArrowUp)
 9558            } else {
 9559                (target_row - current_row, IconName::ArrowDown)
 9560            };
 9561
 9562            h_flex()
 9563                .child(
 9564                    Label::new(format!("{}{}", prefix.into(), row_diff))
 9565                        .color(Color::Muted)
 9566                        .size(LabelSize::Small),
 9567                )
 9568                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 9569        }
 9570
 9571        let supports_jump = self
 9572            .edit_prediction_provider
 9573            .as_ref()
 9574            .map(|provider| provider.provider.supports_jump_to_edit())
 9575            .unwrap_or(true);
 9576
 9577        match &completion.completion {
 9578            EditPrediction::MoveWithin {
 9579                target, snapshot, ..
 9580            } => {
 9581                if !supports_jump {
 9582                    return None;
 9583                }
 9584
 9585                Some(
 9586                    h_flex()
 9587                        .px_2()
 9588                        .gap_2()
 9589                        .flex_1()
 9590                        .child(
 9591                            if target.text_anchor.to_point(snapshot).row > cursor_point.row {
 9592                                Icon::new(IconName::ZedPredictDown)
 9593                            } else {
 9594                                Icon::new(IconName::ZedPredictUp)
 9595                            },
 9596                        )
 9597                        .child(Label::new("Jump to Edit")),
 9598                )
 9599            }
 9600            EditPrediction::MoveOutside { snapshot, .. } => {
 9601                let file_name = snapshot
 9602                    .file()
 9603                    .map(|file| file.file_name(cx))
 9604                    .unwrap_or("untitled");
 9605                Some(
 9606                    h_flex()
 9607                        .px_2()
 9608                        .gap_2()
 9609                        .flex_1()
 9610                        .child(Icon::new(IconName::ZedPredict))
 9611                        .child(Label::new(format!("Jump to {file_name}"))),
 9612                )
 9613            }
 9614            EditPrediction::Edit {
 9615                edits,
 9616                edit_preview,
 9617                snapshot,
 9618                display_mode: _,
 9619            } => {
 9620                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(snapshot).row;
 9621
 9622                let (highlighted_edits, has_more_lines) =
 9623                    if let Some(edit_preview) = edit_preview.as_ref() {
 9624                        crate::edit_prediction_edit_text(snapshot, edits, edit_preview, true, cx)
 9625                            .first_line_preview()
 9626                    } else {
 9627                        crate::edit_prediction_fallback_text(edits, cx).first_line_preview()
 9628                    };
 9629
 9630                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 9631                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 9632
 9633                let preview = h_flex()
 9634                    .gap_1()
 9635                    .min_w_16()
 9636                    .child(styled_text)
 9637                    .when(has_more_lines, |parent| parent.child(""));
 9638
 9639                let left = if supports_jump && first_edit_row != cursor_point.row {
 9640                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 9641                        .into_any_element()
 9642                } else {
 9643                    let icon_name =
 9644                        Editor::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9645                    Icon::new(icon_name).into_any_element()
 9646                };
 9647
 9648                Some(
 9649                    h_flex()
 9650                        .h_full()
 9651                        .flex_1()
 9652                        .gap_2()
 9653                        .pr_1()
 9654                        .overflow_x_hidden()
 9655                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9656                        .child(left)
 9657                        .child(preview),
 9658                )
 9659            }
 9660        }
 9661    }
 9662
 9663    pub fn render_context_menu(
 9664        &self,
 9665        style: &EditorStyle,
 9666        max_height_in_lines: u32,
 9667        window: &mut Window,
 9668        cx: &mut Context<Editor>,
 9669    ) -> Option<AnyElement> {
 9670        let menu = self.context_menu.borrow();
 9671        let menu = menu.as_ref()?;
 9672        if !menu.visible() {
 9673            return None;
 9674        };
 9675        Some(menu.render(style, max_height_in_lines, window, cx))
 9676    }
 9677
 9678    fn render_context_menu_aside(
 9679        &mut self,
 9680        max_size: Size<Pixels>,
 9681        window: &mut Window,
 9682        cx: &mut Context<Editor>,
 9683    ) -> Option<AnyElement> {
 9684        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 9685            if menu.visible() {
 9686                menu.render_aside(max_size, window, cx)
 9687            } else {
 9688                None
 9689            }
 9690        })
 9691    }
 9692
 9693    fn hide_context_menu(
 9694        &mut self,
 9695        window: &mut Window,
 9696        cx: &mut Context<Self>,
 9697    ) -> Option<CodeContextMenu> {
 9698        cx.notify();
 9699        self.completion_tasks.clear();
 9700        let context_menu = self.context_menu.borrow_mut().take();
 9701        self.stale_edit_prediction_in_menu.take();
 9702        self.update_visible_edit_prediction(window, cx);
 9703        if let Some(CodeContextMenu::Completions(_)) = &context_menu
 9704            && let Some(completion_provider) = &self.completion_provider
 9705        {
 9706            completion_provider.selection_changed(None, window, cx);
 9707        }
 9708        context_menu
 9709    }
 9710
 9711    fn show_snippet_choices(
 9712        &mut self,
 9713        choices: &Vec<String>,
 9714        selection: Range<Anchor>,
 9715        cx: &mut Context<Self>,
 9716    ) {
 9717        let Some((_, buffer, _)) = self
 9718            .buffer()
 9719            .read(cx)
 9720            .excerpt_containing(selection.start, cx)
 9721        else {
 9722            return;
 9723        };
 9724        let Some((_, end_buffer, _)) = self.buffer().read(cx).excerpt_containing(selection.end, cx)
 9725        else {
 9726            return;
 9727        };
 9728        if buffer != end_buffer {
 9729            log::error!("expected anchor range to have matching buffer IDs");
 9730            return;
 9731        }
 9732
 9733        let id = post_inc(&mut self.next_completion_id);
 9734        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 9735        *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 9736            CompletionsMenu::new_snippet_choices(
 9737                id,
 9738                true,
 9739                choices,
 9740                selection,
 9741                buffer,
 9742                snippet_sort_order,
 9743            ),
 9744        ));
 9745    }
 9746
 9747    pub fn insert_snippet(
 9748        &mut self,
 9749        insertion_ranges: &[Range<usize>],
 9750        snippet: Snippet,
 9751        window: &mut Window,
 9752        cx: &mut Context<Self>,
 9753    ) -> Result<()> {
 9754        struct Tabstop<T> {
 9755            is_end_tabstop: bool,
 9756            ranges: Vec<Range<T>>,
 9757            choices: Option<Vec<String>>,
 9758        }
 9759
 9760        let tabstops = self.buffer.update(cx, |buffer, cx| {
 9761            let snippet_text: Arc<str> = snippet.text.clone().into();
 9762            let edits = insertion_ranges
 9763                .iter()
 9764                .cloned()
 9765                .map(|range| (range, snippet_text.clone()));
 9766            let autoindent_mode = AutoindentMode::Block {
 9767                original_indent_columns: Vec::new(),
 9768            };
 9769            buffer.edit(edits, Some(autoindent_mode), cx);
 9770
 9771            let snapshot = &*buffer.read(cx);
 9772            let snippet = &snippet;
 9773            snippet
 9774                .tabstops
 9775                .iter()
 9776                .map(|tabstop| {
 9777                    let is_end_tabstop = tabstop.ranges.first().is_some_and(|tabstop| {
 9778                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 9779                    });
 9780                    let mut tabstop_ranges = tabstop
 9781                        .ranges
 9782                        .iter()
 9783                        .flat_map(|tabstop_range| {
 9784                            let mut delta = 0_isize;
 9785                            insertion_ranges.iter().map(move |insertion_range| {
 9786                                let insertion_start = insertion_range.start as isize + delta;
 9787                                delta +=
 9788                                    snippet.text.len() as isize - insertion_range.len() as isize;
 9789
 9790                                let start = ((insertion_start + tabstop_range.start) as usize)
 9791                                    .min(snapshot.len());
 9792                                let end = ((insertion_start + tabstop_range.end) as usize)
 9793                                    .min(snapshot.len());
 9794                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 9795                            })
 9796                        })
 9797                        .collect::<Vec<_>>();
 9798                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 9799
 9800                    Tabstop {
 9801                        is_end_tabstop,
 9802                        ranges: tabstop_ranges,
 9803                        choices: tabstop.choices.clone(),
 9804                    }
 9805                })
 9806                .collect::<Vec<_>>()
 9807        });
 9808        if let Some(tabstop) = tabstops.first() {
 9809            self.change_selections(Default::default(), window, cx, |s| {
 9810                // Reverse order so that the first range is the newest created selection.
 9811                // Completions will use it and autoscroll will prioritize it.
 9812                s.select_ranges(tabstop.ranges.iter().rev().cloned());
 9813            });
 9814
 9815            if let Some(choices) = &tabstop.choices
 9816                && let Some(selection) = tabstop.ranges.first()
 9817            {
 9818                self.show_snippet_choices(choices, selection.clone(), cx)
 9819            }
 9820
 9821            // If we're already at the last tabstop and it's at the end of the snippet,
 9822            // we're done, we don't need to keep the state around.
 9823            if !tabstop.is_end_tabstop {
 9824                let choices = tabstops
 9825                    .iter()
 9826                    .map(|tabstop| tabstop.choices.clone())
 9827                    .collect();
 9828
 9829                let ranges = tabstops
 9830                    .into_iter()
 9831                    .map(|tabstop| tabstop.ranges)
 9832                    .collect::<Vec<_>>();
 9833
 9834                self.snippet_stack.push(SnippetState {
 9835                    active_index: 0,
 9836                    ranges,
 9837                    choices,
 9838                });
 9839            }
 9840
 9841            // Check whether the just-entered snippet ends with an auto-closable bracket.
 9842            if self.autoclose_regions.is_empty() {
 9843                let snapshot = self.buffer.read(cx).snapshot(cx);
 9844                for selection in &mut self.selections.all::<Point>(&self.display_snapshot(cx)) {
 9845                    let selection_head = selection.head();
 9846                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 9847                        continue;
 9848                    };
 9849
 9850                    let mut bracket_pair = None;
 9851                    let max_lookup_length = scope
 9852                        .brackets()
 9853                        .map(|(pair, _)| {
 9854                            pair.start
 9855                                .as_str()
 9856                                .chars()
 9857                                .count()
 9858                                .max(pair.end.as_str().chars().count())
 9859                        })
 9860                        .max();
 9861                    if let Some(max_lookup_length) = max_lookup_length {
 9862                        let next_text = snapshot
 9863                            .chars_at(selection_head)
 9864                            .take(max_lookup_length)
 9865                            .collect::<String>();
 9866                        let prev_text = snapshot
 9867                            .reversed_chars_at(selection_head)
 9868                            .take(max_lookup_length)
 9869                            .collect::<String>();
 9870
 9871                        for (pair, enabled) in scope.brackets() {
 9872                            if enabled
 9873                                && pair.close
 9874                                && prev_text.starts_with(pair.start.as_str())
 9875                                && next_text.starts_with(pair.end.as_str())
 9876                            {
 9877                                bracket_pair = Some(pair.clone());
 9878                                break;
 9879                            }
 9880                        }
 9881                    }
 9882
 9883                    if let Some(pair) = bracket_pair {
 9884                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 9885                        let autoclose_enabled =
 9886                            self.use_autoclose && snapshot_settings.use_autoclose;
 9887                        if autoclose_enabled {
 9888                            let start = snapshot.anchor_after(selection_head);
 9889                            let end = snapshot.anchor_after(selection_head);
 9890                            self.autoclose_regions.push(AutocloseRegion {
 9891                                selection_id: selection.id,
 9892                                range: start..end,
 9893                                pair,
 9894                            });
 9895                        }
 9896                    }
 9897                }
 9898            }
 9899        }
 9900        Ok(())
 9901    }
 9902
 9903    pub fn move_to_next_snippet_tabstop(
 9904        &mut self,
 9905        window: &mut Window,
 9906        cx: &mut Context<Self>,
 9907    ) -> bool {
 9908        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 9909    }
 9910
 9911    pub fn move_to_prev_snippet_tabstop(
 9912        &mut self,
 9913        window: &mut Window,
 9914        cx: &mut Context<Self>,
 9915    ) -> bool {
 9916        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 9917    }
 9918
 9919    pub fn move_to_snippet_tabstop(
 9920        &mut self,
 9921        bias: Bias,
 9922        window: &mut Window,
 9923        cx: &mut Context<Self>,
 9924    ) -> bool {
 9925        if let Some(mut snippet) = self.snippet_stack.pop() {
 9926            match bias {
 9927                Bias::Left => {
 9928                    if snippet.active_index > 0 {
 9929                        snippet.active_index -= 1;
 9930                    } else {
 9931                        self.snippet_stack.push(snippet);
 9932                        return false;
 9933                    }
 9934                }
 9935                Bias::Right => {
 9936                    if snippet.active_index + 1 < snippet.ranges.len() {
 9937                        snippet.active_index += 1;
 9938                    } else {
 9939                        self.snippet_stack.push(snippet);
 9940                        return false;
 9941                    }
 9942                }
 9943            }
 9944            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 9945                self.change_selections(Default::default(), window, cx, |s| {
 9946                    // Reverse order so that the first range is the newest created selection.
 9947                    // Completions will use it and autoscroll will prioritize it.
 9948                    s.select_ranges(current_ranges.iter().rev().cloned())
 9949                });
 9950
 9951                if let Some(choices) = &snippet.choices[snippet.active_index]
 9952                    && let Some(selection) = current_ranges.first()
 9953                {
 9954                    self.show_snippet_choices(choices, selection.clone(), cx);
 9955                }
 9956
 9957                // If snippet state is not at the last tabstop, push it back on the stack
 9958                if snippet.active_index + 1 < snippet.ranges.len() {
 9959                    self.snippet_stack.push(snippet);
 9960                }
 9961                return true;
 9962            }
 9963        }
 9964
 9965        false
 9966    }
 9967
 9968    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 9969        self.transact(window, cx, |this, window, cx| {
 9970            this.select_all(&SelectAll, window, cx);
 9971            this.insert("", window, cx);
 9972        });
 9973    }
 9974
 9975    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
 9976        if self.read_only(cx) {
 9977            return;
 9978        }
 9979        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9980        self.transact(window, cx, |this, window, cx| {
 9981            this.select_autoclose_pair(window, cx);
 9982
 9983            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 9984
 9985            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
 9986            if !this.linked_edit_ranges.is_empty() {
 9987                let selections = this.selections.all::<MultiBufferPoint>(&display_map);
 9988                let snapshot = this.buffer.read(cx).snapshot(cx);
 9989
 9990                for selection in selections.iter() {
 9991                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
 9992                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
 9993                    if selection_start.buffer_id != selection_end.buffer_id {
 9994                        continue;
 9995                    }
 9996                    if let Some(ranges) =
 9997                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
 9998                    {
 9999                        for (buffer, entries) in ranges {
10000                            linked_ranges.entry(buffer).or_default().extend(entries);
10001                        }
10002                    }
10003                }
10004            }
10005
10006            let mut selections = this.selections.all::<MultiBufferPoint>(&display_map);
10007            for selection in &mut selections {
10008                if selection.is_empty() {
10009                    let old_head = selection.head();
10010                    let mut new_head =
10011                        movement::left(&display_map, old_head.to_display_point(&display_map))
10012                            .to_point(&display_map);
10013                    if let Some((buffer, line_buffer_range)) = display_map
10014                        .buffer_snapshot()
10015                        .buffer_line_for_row(MultiBufferRow(old_head.row))
10016                    {
10017                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
10018                        let indent_len = match indent_size.kind {
10019                            IndentKind::Space => {
10020                                buffer.settings_at(line_buffer_range.start, cx).tab_size
10021                            }
10022                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
10023                        };
10024                        if old_head.column <= indent_size.len && old_head.column > 0 {
10025                            let indent_len = indent_len.get();
10026                            new_head = cmp::min(
10027                                new_head,
10028                                MultiBufferPoint::new(
10029                                    old_head.row,
10030                                    ((old_head.column - 1) / indent_len) * indent_len,
10031                                ),
10032                            );
10033                        }
10034                    }
10035
10036                    selection.set_head(new_head, SelectionGoal::None);
10037                }
10038            }
10039
10040            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10041            this.insert("", window, cx);
10042            let empty_str: Arc<str> = Arc::from("");
10043            for (buffer, edits) in linked_ranges {
10044                let snapshot = buffer.read(cx).snapshot();
10045                use text::ToPoint as TP;
10046
10047                let edits = edits
10048                    .into_iter()
10049                    .map(|range| {
10050                        let end_point = TP::to_point(&range.end, &snapshot);
10051                        let mut start_point = TP::to_point(&range.start, &snapshot);
10052
10053                        if end_point == start_point {
10054                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
10055                                .saturating_sub(1);
10056                            start_point =
10057                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
10058                        };
10059
10060                        (start_point..end_point, empty_str.clone())
10061                    })
10062                    .sorted_by_key(|(range, _)| range.start)
10063                    .collect::<Vec<_>>();
10064                buffer.update(cx, |this, cx| {
10065                    this.edit(edits, None, cx);
10066                })
10067            }
10068            this.refresh_edit_prediction(true, false, window, cx);
10069            refresh_linked_ranges(this, window, cx);
10070        });
10071    }
10072
10073    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
10074        if self.read_only(cx) {
10075            return;
10076        }
10077        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10078        self.transact(window, cx, |this, window, cx| {
10079            this.change_selections(Default::default(), window, cx, |s| {
10080                s.move_with(|map, selection| {
10081                    if selection.is_empty() {
10082                        let cursor = movement::right(map, selection.head());
10083                        selection.end = cursor;
10084                        selection.reversed = true;
10085                        selection.goal = SelectionGoal::None;
10086                    }
10087                })
10088            });
10089            this.insert("", window, cx);
10090            this.refresh_edit_prediction(true, false, window, cx);
10091        });
10092    }
10093
10094    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
10095        if self.mode.is_single_line() {
10096            cx.propagate();
10097            return;
10098        }
10099
10100        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10101        if self.move_to_prev_snippet_tabstop(window, cx) {
10102            return;
10103        }
10104        self.outdent(&Outdent, window, cx);
10105    }
10106
10107    pub fn next_snippet_tabstop(
10108        &mut self,
10109        _: &NextSnippetTabstop,
10110        window: &mut Window,
10111        cx: &mut Context<Self>,
10112    ) {
10113        if self.mode.is_single_line() || self.snippet_stack.is_empty() {
10114            cx.propagate();
10115            return;
10116        }
10117
10118        if self.move_to_next_snippet_tabstop(window, cx) {
10119            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10120            return;
10121        }
10122        cx.propagate();
10123    }
10124
10125    pub fn previous_snippet_tabstop(
10126        &mut self,
10127        _: &PreviousSnippetTabstop,
10128        window: &mut Window,
10129        cx: &mut Context<Self>,
10130    ) {
10131        if self.mode.is_single_line() || self.snippet_stack.is_empty() {
10132            cx.propagate();
10133            return;
10134        }
10135
10136        if self.move_to_prev_snippet_tabstop(window, cx) {
10137            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10138            return;
10139        }
10140        cx.propagate();
10141    }
10142
10143    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
10144        if self.mode.is_single_line() {
10145            cx.propagate();
10146            return;
10147        }
10148
10149        if self.move_to_next_snippet_tabstop(window, cx) {
10150            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10151            return;
10152        }
10153        if self.read_only(cx) {
10154            return;
10155        }
10156        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10157        let mut selections = self.selections.all_adjusted(&self.display_snapshot(cx));
10158        let buffer = self.buffer.read(cx);
10159        let snapshot = buffer.snapshot(cx);
10160        let rows_iter = selections.iter().map(|s| s.head().row);
10161        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
10162
10163        let has_some_cursor_in_whitespace = selections
10164            .iter()
10165            .filter(|selection| selection.is_empty())
10166            .any(|selection| {
10167                let cursor = selection.head();
10168                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10169                cursor.column < current_indent.len
10170            });
10171
10172        let mut edits = Vec::new();
10173        let mut prev_edited_row = 0;
10174        let mut row_delta = 0;
10175        for selection in &mut selections {
10176            if selection.start.row != prev_edited_row {
10177                row_delta = 0;
10178            }
10179            prev_edited_row = selection.end.row;
10180
10181            // If the selection is non-empty, then increase the indentation of the selected lines.
10182            if !selection.is_empty() {
10183                row_delta =
10184                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10185                continue;
10186            }
10187
10188            let cursor = selection.head();
10189            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10190            if let Some(suggested_indent) =
10191                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
10192            {
10193                // Don't do anything if already at suggested indent
10194                // and there is any other cursor which is not
10195                if has_some_cursor_in_whitespace
10196                    && cursor.column == current_indent.len
10197                    && current_indent.len == suggested_indent.len
10198                {
10199                    continue;
10200                }
10201
10202                // Adjust line and move cursor to suggested indent
10203                // if cursor is not at suggested indent
10204                if cursor.column < suggested_indent.len
10205                    && cursor.column <= current_indent.len
10206                    && current_indent.len <= suggested_indent.len
10207                {
10208                    selection.start = Point::new(cursor.row, suggested_indent.len);
10209                    selection.end = selection.start;
10210                    if row_delta == 0 {
10211                        edits.extend(Buffer::edit_for_indent_size_adjustment(
10212                            cursor.row,
10213                            current_indent,
10214                            suggested_indent,
10215                        ));
10216                        row_delta = suggested_indent.len - current_indent.len;
10217                    }
10218                    continue;
10219                }
10220
10221                // If current indent is more than suggested indent
10222                // only move cursor to current indent and skip indent
10223                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
10224                    selection.start = Point::new(cursor.row, current_indent.len);
10225                    selection.end = selection.start;
10226                    continue;
10227                }
10228            }
10229
10230            // Otherwise, insert a hard or soft tab.
10231            let settings = buffer.language_settings_at(cursor, cx);
10232            let tab_size = if settings.hard_tabs {
10233                IndentSize::tab()
10234            } else {
10235                let tab_size = settings.tab_size.get();
10236                let indent_remainder = snapshot
10237                    .text_for_range(Point::new(cursor.row, 0)..cursor)
10238                    .flat_map(str::chars)
10239                    .fold(row_delta % tab_size, |counter: u32, c| {
10240                        if c == '\t' {
10241                            0
10242                        } else {
10243                            (counter + 1) % tab_size
10244                        }
10245                    });
10246
10247                let chars_to_next_tab_stop = tab_size - indent_remainder;
10248                IndentSize::spaces(chars_to_next_tab_stop)
10249            };
10250            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
10251            selection.end = selection.start;
10252            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
10253            row_delta += tab_size.len;
10254        }
10255
10256        self.transact(window, cx, |this, window, cx| {
10257            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10258            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10259            this.refresh_edit_prediction(true, false, window, cx);
10260        });
10261    }
10262
10263    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
10264        if self.read_only(cx) {
10265            return;
10266        }
10267        if self.mode.is_single_line() {
10268            cx.propagate();
10269            return;
10270        }
10271
10272        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10273        let mut selections = self.selections.all::<Point>(&self.display_snapshot(cx));
10274        let mut prev_edited_row = 0;
10275        let mut row_delta = 0;
10276        let mut edits = Vec::new();
10277        let buffer = self.buffer.read(cx);
10278        let snapshot = buffer.snapshot(cx);
10279        for selection in &mut selections {
10280            if selection.start.row != prev_edited_row {
10281                row_delta = 0;
10282            }
10283            prev_edited_row = selection.end.row;
10284
10285            row_delta =
10286                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10287        }
10288
10289        self.transact(window, cx, |this, window, cx| {
10290            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10291            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10292        });
10293    }
10294
10295    fn indent_selection(
10296        buffer: &MultiBuffer,
10297        snapshot: &MultiBufferSnapshot,
10298        selection: &mut Selection<Point>,
10299        edits: &mut Vec<(Range<Point>, String)>,
10300        delta_for_start_row: u32,
10301        cx: &App,
10302    ) -> u32 {
10303        let settings = buffer.language_settings_at(selection.start, cx);
10304        let tab_size = settings.tab_size.get();
10305        let indent_kind = if settings.hard_tabs {
10306            IndentKind::Tab
10307        } else {
10308            IndentKind::Space
10309        };
10310        let mut start_row = selection.start.row;
10311        let mut end_row = selection.end.row + 1;
10312
10313        // If a selection ends at the beginning of a line, don't indent
10314        // that last line.
10315        if selection.end.column == 0 && selection.end.row > selection.start.row {
10316            end_row -= 1;
10317        }
10318
10319        // Avoid re-indenting a row that has already been indented by a
10320        // previous selection, but still update this selection's column
10321        // to reflect that indentation.
10322        if delta_for_start_row > 0 {
10323            start_row += 1;
10324            selection.start.column += delta_for_start_row;
10325            if selection.end.row == selection.start.row {
10326                selection.end.column += delta_for_start_row;
10327            }
10328        }
10329
10330        let mut delta_for_end_row = 0;
10331        let has_multiple_rows = start_row + 1 != end_row;
10332        for row in start_row..end_row {
10333            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
10334            let indent_delta = match (current_indent.kind, indent_kind) {
10335                (IndentKind::Space, IndentKind::Space) => {
10336                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
10337                    IndentSize::spaces(columns_to_next_tab_stop)
10338                }
10339                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
10340                (_, IndentKind::Tab) => IndentSize::tab(),
10341            };
10342
10343            let start = if has_multiple_rows || current_indent.len < selection.start.column {
10344                0
10345            } else {
10346                selection.start.column
10347            };
10348            let row_start = Point::new(row, start);
10349            edits.push((
10350                row_start..row_start,
10351                indent_delta.chars().collect::<String>(),
10352            ));
10353
10354            // Update this selection's endpoints to reflect the indentation.
10355            if row == selection.start.row {
10356                selection.start.column += indent_delta.len;
10357            }
10358            if row == selection.end.row {
10359                selection.end.column += indent_delta.len;
10360                delta_for_end_row = indent_delta.len;
10361            }
10362        }
10363
10364        if selection.start.row == selection.end.row {
10365            delta_for_start_row + delta_for_end_row
10366        } else {
10367            delta_for_end_row
10368        }
10369    }
10370
10371    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
10372        if self.read_only(cx) {
10373            return;
10374        }
10375        if self.mode.is_single_line() {
10376            cx.propagate();
10377            return;
10378        }
10379
10380        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10381        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10382        let selections = self.selections.all::<Point>(&display_map);
10383        let mut deletion_ranges = Vec::new();
10384        let mut last_outdent = None;
10385        {
10386            let buffer = self.buffer.read(cx);
10387            let snapshot = buffer.snapshot(cx);
10388            for selection in &selections {
10389                let settings = buffer.language_settings_at(selection.start, cx);
10390                let tab_size = settings.tab_size.get();
10391                let mut rows = selection.spanned_rows(false, &display_map);
10392
10393                // Avoid re-outdenting a row that has already been outdented by a
10394                // previous selection.
10395                if let Some(last_row) = last_outdent
10396                    && last_row == rows.start
10397                {
10398                    rows.start = rows.start.next_row();
10399                }
10400                let has_multiple_rows = rows.len() > 1;
10401                for row in rows.iter_rows() {
10402                    let indent_size = snapshot.indent_size_for_line(row);
10403                    if indent_size.len > 0 {
10404                        let deletion_len = match indent_size.kind {
10405                            IndentKind::Space => {
10406                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
10407                                if columns_to_prev_tab_stop == 0 {
10408                                    tab_size
10409                                } else {
10410                                    columns_to_prev_tab_stop
10411                                }
10412                            }
10413                            IndentKind::Tab => 1,
10414                        };
10415                        let start = if has_multiple_rows
10416                            || deletion_len > selection.start.column
10417                            || indent_size.len < selection.start.column
10418                        {
10419                            0
10420                        } else {
10421                            selection.start.column - deletion_len
10422                        };
10423                        deletion_ranges.push(
10424                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
10425                        );
10426                        last_outdent = Some(row);
10427                    }
10428                }
10429            }
10430        }
10431
10432        self.transact(window, cx, |this, window, cx| {
10433            this.buffer.update(cx, |buffer, cx| {
10434                let empty_str: Arc<str> = Arc::default();
10435                buffer.edit(
10436                    deletion_ranges
10437                        .into_iter()
10438                        .map(|range| (range, empty_str.clone())),
10439                    None,
10440                    cx,
10441                );
10442            });
10443            let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
10444            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10445        });
10446    }
10447
10448    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
10449        if self.read_only(cx) {
10450            return;
10451        }
10452        if self.mode.is_single_line() {
10453            cx.propagate();
10454            return;
10455        }
10456
10457        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10458        let selections = self
10459            .selections
10460            .all::<usize>(&self.display_snapshot(cx))
10461            .into_iter()
10462            .map(|s| s.range());
10463
10464        self.transact(window, cx, |this, window, cx| {
10465            this.buffer.update(cx, |buffer, cx| {
10466                buffer.autoindent_ranges(selections, cx);
10467            });
10468            let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
10469            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10470        });
10471    }
10472
10473    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
10474        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10475        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10476        let selections = self.selections.all::<Point>(&display_map);
10477
10478        let mut new_cursors = Vec::new();
10479        let mut edit_ranges = Vec::new();
10480        let mut selections = selections.iter().peekable();
10481        while let Some(selection) = selections.next() {
10482            let mut rows = selection.spanned_rows(false, &display_map);
10483
10484            // Accumulate contiguous regions of rows that we want to delete.
10485            while let Some(next_selection) = selections.peek() {
10486                let next_rows = next_selection.spanned_rows(false, &display_map);
10487                if next_rows.start <= rows.end {
10488                    rows.end = next_rows.end;
10489                    selections.next().unwrap();
10490                } else {
10491                    break;
10492                }
10493            }
10494
10495            let buffer = display_map.buffer_snapshot();
10496            let mut edit_start = ToOffset::to_offset(&Point::new(rows.start.0, 0), buffer);
10497            let (edit_end, target_row) = if buffer.max_point().row >= rows.end.0 {
10498                // If there's a line after the range, delete the \n from the end of the row range
10499                (
10500                    ToOffset::to_offset(&Point::new(rows.end.0, 0), buffer),
10501                    rows.end,
10502                )
10503            } else {
10504                // If there isn't a line after the range, delete the \n from the line before the
10505                // start of the row range
10506                edit_start = edit_start.saturating_sub(1);
10507                (buffer.len(), rows.start.previous_row())
10508            };
10509
10510            let text_layout_details = self.text_layout_details(window);
10511            let x = display_map.x_for_display_point(
10512                selection.head().to_display_point(&display_map),
10513                &text_layout_details,
10514            );
10515            let row = Point::new(target_row.0, 0)
10516                .to_display_point(&display_map)
10517                .row();
10518            let column = display_map.display_column_for_x(row, x, &text_layout_details);
10519
10520            new_cursors.push((
10521                selection.id,
10522                buffer.anchor_after(DisplayPoint::new(row, column).to_point(&display_map)),
10523                SelectionGoal::None,
10524            ));
10525            edit_ranges.push(edit_start..edit_end);
10526        }
10527
10528        self.transact(window, cx, |this, window, cx| {
10529            let buffer = this.buffer.update(cx, |buffer, cx| {
10530                let empty_str: Arc<str> = Arc::default();
10531                buffer.edit(
10532                    edit_ranges
10533                        .into_iter()
10534                        .map(|range| (range, empty_str.clone())),
10535                    None,
10536                    cx,
10537                );
10538                buffer.snapshot(cx)
10539            });
10540            let new_selections = new_cursors
10541                .into_iter()
10542                .map(|(id, cursor, goal)| {
10543                    let cursor = cursor.to_point(&buffer);
10544                    Selection {
10545                        id,
10546                        start: cursor,
10547                        end: cursor,
10548                        reversed: false,
10549                        goal,
10550                    }
10551                })
10552                .collect();
10553
10554            this.change_selections(Default::default(), window, cx, |s| {
10555                s.select(new_selections);
10556            });
10557        });
10558    }
10559
10560    pub fn join_lines_impl(
10561        &mut self,
10562        insert_whitespace: bool,
10563        window: &mut Window,
10564        cx: &mut Context<Self>,
10565    ) {
10566        if self.read_only(cx) {
10567            return;
10568        }
10569        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
10570        for selection in self.selections.all::<Point>(&self.display_snapshot(cx)) {
10571            let start = MultiBufferRow(selection.start.row);
10572            // Treat single line selections as if they include the next line. Otherwise this action
10573            // would do nothing for single line selections individual cursors.
10574            let end = if selection.start.row == selection.end.row {
10575                MultiBufferRow(selection.start.row + 1)
10576            } else {
10577                MultiBufferRow(selection.end.row)
10578            };
10579
10580            if let Some(last_row_range) = row_ranges.last_mut()
10581                && start <= last_row_range.end
10582            {
10583                last_row_range.end = end;
10584                continue;
10585            }
10586            row_ranges.push(start..end);
10587        }
10588
10589        let snapshot = self.buffer.read(cx).snapshot(cx);
10590        let mut cursor_positions = Vec::new();
10591        for row_range in &row_ranges {
10592            let anchor = snapshot.anchor_before(Point::new(
10593                row_range.end.previous_row().0,
10594                snapshot.line_len(row_range.end.previous_row()),
10595            ));
10596            cursor_positions.push(anchor..anchor);
10597        }
10598
10599        self.transact(window, cx, |this, window, cx| {
10600            for row_range in row_ranges.into_iter().rev() {
10601                for row in row_range.iter_rows().rev() {
10602                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
10603                    let next_line_row = row.next_row();
10604                    let indent = snapshot.indent_size_for_line(next_line_row);
10605                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
10606
10607                    let replace =
10608                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
10609                            " "
10610                        } else {
10611                            ""
10612                        };
10613
10614                    this.buffer.update(cx, |buffer, cx| {
10615                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
10616                    });
10617                }
10618            }
10619
10620            this.change_selections(Default::default(), window, cx, |s| {
10621                s.select_anchor_ranges(cursor_positions)
10622            });
10623        });
10624    }
10625
10626    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
10627        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10628        self.join_lines_impl(true, window, cx);
10629    }
10630
10631    pub fn sort_lines_case_sensitive(
10632        &mut self,
10633        _: &SortLinesCaseSensitive,
10634        window: &mut Window,
10635        cx: &mut Context<Self>,
10636    ) {
10637        self.manipulate_immutable_lines(window, cx, |lines| lines.sort())
10638    }
10639
10640    pub fn sort_lines_by_length(
10641        &mut self,
10642        _: &SortLinesByLength,
10643        window: &mut Window,
10644        cx: &mut Context<Self>,
10645    ) {
10646        self.manipulate_immutable_lines(window, cx, |lines| {
10647            lines.sort_by_key(|&line| line.chars().count())
10648        })
10649    }
10650
10651    pub fn sort_lines_case_insensitive(
10652        &mut self,
10653        _: &SortLinesCaseInsensitive,
10654        window: &mut Window,
10655        cx: &mut Context<Self>,
10656    ) {
10657        self.manipulate_immutable_lines(window, cx, |lines| {
10658            lines.sort_by_key(|line| line.to_lowercase())
10659        })
10660    }
10661
10662    pub fn unique_lines_case_insensitive(
10663        &mut self,
10664        _: &UniqueLinesCaseInsensitive,
10665        window: &mut Window,
10666        cx: &mut Context<Self>,
10667    ) {
10668        self.manipulate_immutable_lines(window, cx, |lines| {
10669            let mut seen = HashSet::default();
10670            lines.retain(|line| seen.insert(line.to_lowercase()));
10671        })
10672    }
10673
10674    pub fn unique_lines_case_sensitive(
10675        &mut self,
10676        _: &UniqueLinesCaseSensitive,
10677        window: &mut Window,
10678        cx: &mut Context<Self>,
10679    ) {
10680        self.manipulate_immutable_lines(window, cx, |lines| {
10681            let mut seen = HashSet::default();
10682            lines.retain(|line| seen.insert(*line));
10683        })
10684    }
10685
10686    fn enable_wrap_selections_in_tag(&self, cx: &App) -> bool {
10687        let snapshot = self.buffer.read(cx).snapshot(cx);
10688        for selection in self.selections.disjoint_anchors_arc().iter() {
10689            if snapshot
10690                .language_at(selection.start)
10691                .and_then(|lang| lang.config().wrap_characters.as_ref())
10692                .is_some()
10693            {
10694                return true;
10695            }
10696        }
10697        false
10698    }
10699
10700    fn wrap_selections_in_tag(
10701        &mut self,
10702        _: &WrapSelectionsInTag,
10703        window: &mut Window,
10704        cx: &mut Context<Self>,
10705    ) {
10706        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10707
10708        let snapshot = self.buffer.read(cx).snapshot(cx);
10709
10710        let mut edits = Vec::new();
10711        let mut boundaries = Vec::new();
10712
10713        for selection in self
10714            .selections
10715            .all_adjusted(&self.display_snapshot(cx))
10716            .iter()
10717        {
10718            let Some(wrap_config) = snapshot
10719                .language_at(selection.start)
10720                .and_then(|lang| lang.config().wrap_characters.clone())
10721            else {
10722                continue;
10723            };
10724
10725            let open_tag = format!("{}{}", wrap_config.start_prefix, wrap_config.start_suffix);
10726            let close_tag = format!("{}{}", wrap_config.end_prefix, wrap_config.end_suffix);
10727
10728            let start_before = snapshot.anchor_before(selection.start);
10729            let end_after = snapshot.anchor_after(selection.end);
10730
10731            edits.push((start_before..start_before, open_tag));
10732            edits.push((end_after..end_after, close_tag));
10733
10734            boundaries.push((
10735                start_before,
10736                end_after,
10737                wrap_config.start_prefix.len(),
10738                wrap_config.end_suffix.len(),
10739            ));
10740        }
10741
10742        if edits.is_empty() {
10743            return;
10744        }
10745
10746        self.transact(window, cx, |this, window, cx| {
10747            let buffer = this.buffer.update(cx, |buffer, cx| {
10748                buffer.edit(edits, None, cx);
10749                buffer.snapshot(cx)
10750            });
10751
10752            let mut new_selections = Vec::with_capacity(boundaries.len() * 2);
10753            for (start_before, end_after, start_prefix_len, end_suffix_len) in
10754                boundaries.into_iter()
10755            {
10756                let open_offset = start_before.to_offset(&buffer) + start_prefix_len;
10757                let close_offset = end_after.to_offset(&buffer).saturating_sub(end_suffix_len);
10758                new_selections.push(open_offset..open_offset);
10759                new_selections.push(close_offset..close_offset);
10760            }
10761
10762            this.change_selections(Default::default(), window, cx, |s| {
10763                s.select_ranges(new_selections);
10764            });
10765
10766            this.request_autoscroll(Autoscroll::fit(), cx);
10767        });
10768    }
10769
10770    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
10771        let Some(project) = self.project.clone() else {
10772            return;
10773        };
10774        self.reload(project, window, cx)
10775            .detach_and_notify_err(window, cx);
10776    }
10777
10778    pub fn restore_file(
10779        &mut self,
10780        _: &::git::RestoreFile,
10781        window: &mut Window,
10782        cx: &mut Context<Self>,
10783    ) {
10784        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10785        let mut buffer_ids = HashSet::default();
10786        let snapshot = self.buffer().read(cx).snapshot(cx);
10787        for selection in self.selections.all::<usize>(&self.display_snapshot(cx)) {
10788            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
10789        }
10790
10791        let buffer = self.buffer().read(cx);
10792        let ranges = buffer_ids
10793            .into_iter()
10794            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
10795            .collect::<Vec<_>>();
10796
10797        self.restore_hunks_in_ranges(ranges, window, cx);
10798    }
10799
10800    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
10801        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10802        let selections = self
10803            .selections
10804            .all(&self.display_snapshot(cx))
10805            .into_iter()
10806            .map(|s| s.range())
10807            .collect();
10808        self.restore_hunks_in_ranges(selections, window, cx);
10809    }
10810
10811    pub fn restore_hunks_in_ranges(
10812        &mut self,
10813        ranges: Vec<Range<Point>>,
10814        window: &mut Window,
10815        cx: &mut Context<Editor>,
10816    ) {
10817        let mut revert_changes = HashMap::default();
10818        let chunk_by = self
10819            .snapshot(window, cx)
10820            .hunks_for_ranges(ranges)
10821            .into_iter()
10822            .chunk_by(|hunk| hunk.buffer_id);
10823        for (buffer_id, hunks) in &chunk_by {
10824            let hunks = hunks.collect::<Vec<_>>();
10825            for hunk in &hunks {
10826                self.prepare_restore_change(&mut revert_changes, hunk, cx);
10827            }
10828            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
10829        }
10830        drop(chunk_by);
10831        if !revert_changes.is_empty() {
10832            self.transact(window, cx, |editor, window, cx| {
10833                editor.restore(revert_changes, window, cx);
10834            });
10835        }
10836    }
10837
10838    pub fn status_for_buffer_id(&self, buffer_id: BufferId, cx: &App) -> Option<FileStatus> {
10839        if let Some(status) = self
10840            .addons
10841            .iter()
10842            .find_map(|(_, addon)| addon.override_status_for_buffer_id(buffer_id, cx))
10843        {
10844            return Some(status);
10845        }
10846        self.project
10847            .as_ref()?
10848            .read(cx)
10849            .status_for_buffer_id(buffer_id, cx)
10850    }
10851
10852    pub fn open_active_item_in_terminal(
10853        &mut self,
10854        _: &OpenInTerminal,
10855        window: &mut Window,
10856        cx: &mut Context<Self>,
10857    ) {
10858        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
10859            let project_path = buffer.read(cx).project_path(cx)?;
10860            let project = self.project()?.read(cx);
10861            let entry = project.entry_for_path(&project_path, cx)?;
10862            let parent = match &entry.canonical_path {
10863                Some(canonical_path) => canonical_path.to_path_buf(),
10864                None => project.absolute_path(&project_path, cx)?,
10865            }
10866            .parent()?
10867            .to_path_buf();
10868            Some(parent)
10869        }) {
10870            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
10871        }
10872    }
10873
10874    fn set_breakpoint_context_menu(
10875        &mut self,
10876        display_row: DisplayRow,
10877        position: Option<Anchor>,
10878        clicked_point: gpui::Point<Pixels>,
10879        window: &mut Window,
10880        cx: &mut Context<Self>,
10881    ) {
10882        let source = self
10883            .buffer
10884            .read(cx)
10885            .snapshot(cx)
10886            .anchor_before(Point::new(display_row.0, 0u32));
10887
10888        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
10889
10890        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
10891            self,
10892            source,
10893            clicked_point,
10894            context_menu,
10895            window,
10896            cx,
10897        );
10898    }
10899
10900    fn add_edit_breakpoint_block(
10901        &mut self,
10902        anchor: Anchor,
10903        breakpoint: &Breakpoint,
10904        edit_action: BreakpointPromptEditAction,
10905        window: &mut Window,
10906        cx: &mut Context<Self>,
10907    ) {
10908        let weak_editor = cx.weak_entity();
10909        let bp_prompt = cx.new(|cx| {
10910            BreakpointPromptEditor::new(
10911                weak_editor,
10912                anchor,
10913                breakpoint.clone(),
10914                edit_action,
10915                window,
10916                cx,
10917            )
10918        });
10919
10920        let height = bp_prompt.update(cx, |this, cx| {
10921            this.prompt
10922                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
10923        });
10924        let cloned_prompt = bp_prompt.clone();
10925        let blocks = vec![BlockProperties {
10926            style: BlockStyle::Sticky,
10927            placement: BlockPlacement::Above(anchor),
10928            height: Some(height),
10929            render: Arc::new(move |cx| {
10930                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
10931                cloned_prompt.clone().into_any_element()
10932            }),
10933            priority: 0,
10934        }];
10935
10936        let focus_handle = bp_prompt.focus_handle(cx);
10937        window.focus(&focus_handle);
10938
10939        let block_ids = self.insert_blocks(blocks, None, cx);
10940        bp_prompt.update(cx, |prompt, _| {
10941            prompt.add_block_ids(block_ids);
10942        });
10943    }
10944
10945    pub(crate) fn breakpoint_at_row(
10946        &self,
10947        row: u32,
10948        window: &mut Window,
10949        cx: &mut Context<Self>,
10950    ) -> Option<(Anchor, Breakpoint)> {
10951        let snapshot = self.snapshot(window, cx);
10952        let breakpoint_position = snapshot.buffer_snapshot().anchor_before(Point::new(row, 0));
10953
10954        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10955    }
10956
10957    pub(crate) fn breakpoint_at_anchor(
10958        &self,
10959        breakpoint_position: Anchor,
10960        snapshot: &EditorSnapshot,
10961        cx: &mut Context<Self>,
10962    ) -> Option<(Anchor, Breakpoint)> {
10963        let buffer = self
10964            .buffer
10965            .read(cx)
10966            .buffer_for_anchor(breakpoint_position, cx)?;
10967
10968        let enclosing_excerpt = breakpoint_position.excerpt_id;
10969        let buffer_snapshot = buffer.read(cx).snapshot();
10970
10971        let row = buffer_snapshot
10972            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
10973            .row;
10974
10975        let line_len = snapshot.buffer_snapshot().line_len(MultiBufferRow(row));
10976        let anchor_end = snapshot
10977            .buffer_snapshot()
10978            .anchor_after(Point::new(row, line_len));
10979
10980        self.breakpoint_store
10981            .as_ref()?
10982            .read_with(cx, |breakpoint_store, cx| {
10983                breakpoint_store
10984                    .breakpoints(
10985                        &buffer,
10986                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
10987                        &buffer_snapshot,
10988                        cx,
10989                    )
10990                    .next()
10991                    .and_then(|(bp, _)| {
10992                        let breakpoint_row = buffer_snapshot
10993                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
10994                            .row;
10995
10996                        if breakpoint_row == row {
10997                            snapshot
10998                                .buffer_snapshot()
10999                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
11000                                .map(|position| (position, bp.bp.clone()))
11001                        } else {
11002                            None
11003                        }
11004                    })
11005            })
11006    }
11007
11008    pub fn edit_log_breakpoint(
11009        &mut self,
11010        _: &EditLogBreakpoint,
11011        window: &mut Window,
11012        cx: &mut Context<Self>,
11013    ) {
11014        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11015            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
11016                message: None,
11017                state: BreakpointState::Enabled,
11018                condition: None,
11019                hit_condition: None,
11020            });
11021
11022            self.add_edit_breakpoint_block(
11023                anchor,
11024                &breakpoint,
11025                BreakpointPromptEditAction::Log,
11026                window,
11027                cx,
11028            );
11029        }
11030    }
11031
11032    fn breakpoints_at_cursors(
11033        &self,
11034        window: &mut Window,
11035        cx: &mut Context<Self>,
11036    ) -> Vec<(Anchor, Option<Breakpoint>)> {
11037        let snapshot = self.snapshot(window, cx);
11038        let cursors = self
11039            .selections
11040            .disjoint_anchors_arc()
11041            .iter()
11042            .map(|selection| {
11043                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot());
11044
11045                let breakpoint_position = self
11046                    .breakpoint_at_row(cursor_position.row, window, cx)
11047                    .map(|bp| bp.0)
11048                    .unwrap_or_else(|| {
11049                        snapshot
11050                            .display_snapshot
11051                            .buffer_snapshot()
11052                            .anchor_after(Point::new(cursor_position.row, 0))
11053                    });
11054
11055                let breakpoint = self
11056                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
11057                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
11058
11059                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
11060            })
11061            // 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.
11062            .collect::<HashMap<Anchor, _>>();
11063
11064        cursors.into_iter().collect()
11065    }
11066
11067    pub fn enable_breakpoint(
11068        &mut self,
11069        _: &crate::actions::EnableBreakpoint,
11070        window: &mut Window,
11071        cx: &mut Context<Self>,
11072    ) {
11073        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11074            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
11075                continue;
11076            };
11077            self.edit_breakpoint_at_anchor(
11078                anchor,
11079                breakpoint,
11080                BreakpointEditAction::InvertState,
11081                cx,
11082            );
11083        }
11084    }
11085
11086    pub fn disable_breakpoint(
11087        &mut self,
11088        _: &crate::actions::DisableBreakpoint,
11089        window: &mut Window,
11090        cx: &mut Context<Self>,
11091    ) {
11092        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11093            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
11094                continue;
11095            };
11096            self.edit_breakpoint_at_anchor(
11097                anchor,
11098                breakpoint,
11099                BreakpointEditAction::InvertState,
11100                cx,
11101            );
11102        }
11103    }
11104
11105    pub fn toggle_breakpoint(
11106        &mut self,
11107        _: &crate::actions::ToggleBreakpoint,
11108        window: &mut Window,
11109        cx: &mut Context<Self>,
11110    ) {
11111        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11112            if let Some(breakpoint) = breakpoint {
11113                self.edit_breakpoint_at_anchor(
11114                    anchor,
11115                    breakpoint,
11116                    BreakpointEditAction::Toggle,
11117                    cx,
11118                );
11119            } else {
11120                self.edit_breakpoint_at_anchor(
11121                    anchor,
11122                    Breakpoint::new_standard(),
11123                    BreakpointEditAction::Toggle,
11124                    cx,
11125                );
11126            }
11127        }
11128    }
11129
11130    pub fn edit_breakpoint_at_anchor(
11131        &mut self,
11132        breakpoint_position: Anchor,
11133        breakpoint: Breakpoint,
11134        edit_action: BreakpointEditAction,
11135        cx: &mut Context<Self>,
11136    ) {
11137        let Some(breakpoint_store) = &self.breakpoint_store else {
11138            return;
11139        };
11140
11141        let Some(buffer) = self
11142            .buffer
11143            .read(cx)
11144            .buffer_for_anchor(breakpoint_position, cx)
11145        else {
11146            return;
11147        };
11148
11149        breakpoint_store.update(cx, |breakpoint_store, cx| {
11150            breakpoint_store.toggle_breakpoint(
11151                buffer,
11152                BreakpointWithPosition {
11153                    position: breakpoint_position.text_anchor,
11154                    bp: breakpoint,
11155                },
11156                edit_action,
11157                cx,
11158            );
11159        });
11160
11161        cx.notify();
11162    }
11163
11164    #[cfg(any(test, feature = "test-support"))]
11165    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
11166        self.breakpoint_store.clone()
11167    }
11168
11169    pub fn prepare_restore_change(
11170        &self,
11171        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
11172        hunk: &MultiBufferDiffHunk,
11173        cx: &mut App,
11174    ) -> Option<()> {
11175        if hunk.is_created_file() {
11176            return None;
11177        }
11178        let buffer = self.buffer.read(cx);
11179        let diff = buffer.diff_for(hunk.buffer_id)?;
11180        let buffer = buffer.buffer(hunk.buffer_id)?;
11181        let buffer = buffer.read(cx);
11182        let original_text = diff
11183            .read(cx)
11184            .base_text()
11185            .as_rope()
11186            .slice(hunk.diff_base_byte_range.clone());
11187        let buffer_snapshot = buffer.snapshot();
11188        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
11189        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
11190            probe
11191                .0
11192                .start
11193                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
11194                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
11195        }) {
11196            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
11197            Some(())
11198        } else {
11199            None
11200        }
11201    }
11202
11203    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
11204        self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())
11205    }
11206
11207    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
11208        self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut rand::rng()))
11209    }
11210
11211    fn manipulate_lines<M>(
11212        &mut self,
11213        window: &mut Window,
11214        cx: &mut Context<Self>,
11215        mut manipulate: M,
11216    ) where
11217        M: FnMut(&str) -> LineManipulationResult,
11218    {
11219        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11220
11221        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11222        let buffer = self.buffer.read(cx).snapshot(cx);
11223
11224        let mut edits = Vec::new();
11225
11226        let selections = self.selections.all::<Point>(&display_map);
11227        let mut selections = selections.iter().peekable();
11228        let mut contiguous_row_selections = Vec::new();
11229        let mut new_selections = Vec::new();
11230        let mut added_lines = 0;
11231        let mut removed_lines = 0;
11232
11233        while let Some(selection) = selections.next() {
11234            let (start_row, end_row) = consume_contiguous_rows(
11235                &mut contiguous_row_selections,
11236                selection,
11237                &display_map,
11238                &mut selections,
11239            );
11240
11241            let start_point = Point::new(start_row.0, 0);
11242            let end_point = Point::new(
11243                end_row.previous_row().0,
11244                buffer.line_len(end_row.previous_row()),
11245            );
11246            let text = buffer
11247                .text_for_range(start_point..end_point)
11248                .collect::<String>();
11249
11250            let LineManipulationResult {
11251                new_text,
11252                line_count_before,
11253                line_count_after,
11254            } = manipulate(&text);
11255
11256            edits.push((start_point..end_point, new_text));
11257
11258            // Selections must change based on added and removed line count
11259            let start_row =
11260                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
11261            let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);
11262            new_selections.push(Selection {
11263                id: selection.id,
11264                start: start_row,
11265                end: end_row,
11266                goal: SelectionGoal::None,
11267                reversed: selection.reversed,
11268            });
11269
11270            if line_count_after > line_count_before {
11271                added_lines += line_count_after - line_count_before;
11272            } else if line_count_before > line_count_after {
11273                removed_lines += line_count_before - line_count_after;
11274            }
11275        }
11276
11277        self.transact(window, cx, |this, window, cx| {
11278            let buffer = this.buffer.update(cx, |buffer, cx| {
11279                buffer.edit(edits, None, cx);
11280                buffer.snapshot(cx)
11281            });
11282
11283            // Recalculate offsets on newly edited buffer
11284            let new_selections = new_selections
11285                .iter()
11286                .map(|s| {
11287                    let start_point = Point::new(s.start.0, 0);
11288                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
11289                    Selection {
11290                        id: s.id,
11291                        start: buffer.point_to_offset(start_point),
11292                        end: buffer.point_to_offset(end_point),
11293                        goal: s.goal,
11294                        reversed: s.reversed,
11295                    }
11296                })
11297                .collect();
11298
11299            this.change_selections(Default::default(), window, cx, |s| {
11300                s.select(new_selections);
11301            });
11302
11303            this.request_autoscroll(Autoscroll::fit(), cx);
11304        });
11305    }
11306
11307    fn manipulate_immutable_lines<Fn>(
11308        &mut self,
11309        window: &mut Window,
11310        cx: &mut Context<Self>,
11311        mut callback: Fn,
11312    ) where
11313        Fn: FnMut(&mut Vec<&str>),
11314    {
11315        self.manipulate_lines(window, cx, |text| {
11316            let mut lines: Vec<&str> = text.split('\n').collect();
11317            let line_count_before = lines.len();
11318
11319            callback(&mut lines);
11320
11321            LineManipulationResult {
11322                new_text: lines.join("\n"),
11323                line_count_before,
11324                line_count_after: lines.len(),
11325            }
11326        });
11327    }
11328
11329    fn manipulate_mutable_lines<Fn>(
11330        &mut self,
11331        window: &mut Window,
11332        cx: &mut Context<Self>,
11333        mut callback: Fn,
11334    ) where
11335        Fn: FnMut(&mut Vec<Cow<'_, str>>),
11336    {
11337        self.manipulate_lines(window, cx, |text| {
11338            let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
11339            let line_count_before = lines.len();
11340
11341            callback(&mut lines);
11342
11343            LineManipulationResult {
11344                new_text: lines.join("\n"),
11345                line_count_before,
11346                line_count_after: lines.len(),
11347            }
11348        });
11349    }
11350
11351    pub fn convert_indentation_to_spaces(
11352        &mut self,
11353        _: &ConvertIndentationToSpaces,
11354        window: &mut Window,
11355        cx: &mut Context<Self>,
11356    ) {
11357        let settings = self.buffer.read(cx).language_settings(cx);
11358        let tab_size = settings.tab_size.get() as usize;
11359
11360        self.manipulate_mutable_lines(window, cx, |lines| {
11361            // Allocates a reasonably sized scratch buffer once for the whole loop
11362            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11363            // Avoids recomputing spaces that could be inserted many times
11364            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11365                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11366                .collect();
11367
11368            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11369                let mut chars = line.as_ref().chars();
11370                let mut col = 0;
11371                let mut changed = false;
11372
11373                for ch in chars.by_ref() {
11374                    match ch {
11375                        ' ' => {
11376                            reindented_line.push(' ');
11377                            col += 1;
11378                        }
11379                        '\t' => {
11380                            // \t are converted to spaces depending on the current column
11381                            let spaces_len = tab_size - (col % tab_size);
11382                            reindented_line.extend(&space_cache[spaces_len - 1]);
11383                            col += spaces_len;
11384                            changed = true;
11385                        }
11386                        _ => {
11387                            // If we dont append before break, the character is consumed
11388                            reindented_line.push(ch);
11389                            break;
11390                        }
11391                    }
11392                }
11393
11394                if !changed {
11395                    reindented_line.clear();
11396                    continue;
11397                }
11398                // Append the rest of the line and replace old reference with new one
11399                reindented_line.extend(chars);
11400                *line = Cow::Owned(reindented_line.clone());
11401                reindented_line.clear();
11402            }
11403        });
11404    }
11405
11406    pub fn convert_indentation_to_tabs(
11407        &mut self,
11408        _: &ConvertIndentationToTabs,
11409        window: &mut Window,
11410        cx: &mut Context<Self>,
11411    ) {
11412        let settings = self.buffer.read(cx).language_settings(cx);
11413        let tab_size = settings.tab_size.get() as usize;
11414
11415        self.manipulate_mutable_lines(window, cx, |lines| {
11416            // Allocates a reasonably sized buffer once for the whole loop
11417            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11418            // Avoids recomputing spaces that could be inserted many times
11419            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11420                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11421                .collect();
11422
11423            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11424                let mut chars = line.chars();
11425                let mut spaces_count = 0;
11426                let mut first_non_indent_char = None;
11427                let mut changed = false;
11428
11429                for ch in chars.by_ref() {
11430                    match ch {
11431                        ' ' => {
11432                            // Keep track of spaces. Append \t when we reach tab_size
11433                            spaces_count += 1;
11434                            changed = true;
11435                            if spaces_count == tab_size {
11436                                reindented_line.push('\t');
11437                                spaces_count = 0;
11438                            }
11439                        }
11440                        '\t' => {
11441                            reindented_line.push('\t');
11442                            spaces_count = 0;
11443                        }
11444                        _ => {
11445                            // Dont append it yet, we might have remaining spaces
11446                            first_non_indent_char = Some(ch);
11447                            break;
11448                        }
11449                    }
11450                }
11451
11452                if !changed {
11453                    reindented_line.clear();
11454                    continue;
11455                }
11456                // Remaining spaces that didn't make a full tab stop
11457                if spaces_count > 0 {
11458                    reindented_line.extend(&space_cache[spaces_count - 1]);
11459                }
11460                // If we consume an extra character that was not indentation, add it back
11461                if let Some(extra_char) = first_non_indent_char {
11462                    reindented_line.push(extra_char);
11463                }
11464                // Append the rest of the line and replace old reference with new one
11465                reindented_line.extend(chars);
11466                *line = Cow::Owned(reindented_line.clone());
11467                reindented_line.clear();
11468            }
11469        });
11470    }
11471
11472    pub fn convert_to_upper_case(
11473        &mut self,
11474        _: &ConvertToUpperCase,
11475        window: &mut Window,
11476        cx: &mut Context<Self>,
11477    ) {
11478        self.manipulate_text(window, cx, |text| text.to_uppercase())
11479    }
11480
11481    pub fn convert_to_lower_case(
11482        &mut self,
11483        _: &ConvertToLowerCase,
11484        window: &mut Window,
11485        cx: &mut Context<Self>,
11486    ) {
11487        self.manipulate_text(window, cx, |text| text.to_lowercase())
11488    }
11489
11490    pub fn convert_to_title_case(
11491        &mut self,
11492        _: &ConvertToTitleCase,
11493        window: &mut Window,
11494        cx: &mut Context<Self>,
11495    ) {
11496        self.manipulate_text(window, cx, |text| {
11497            text.split('\n')
11498                .map(|line| line.to_case(Case::Title))
11499                .join("\n")
11500        })
11501    }
11502
11503    pub fn convert_to_snake_case(
11504        &mut self,
11505        _: &ConvertToSnakeCase,
11506        window: &mut Window,
11507        cx: &mut Context<Self>,
11508    ) {
11509        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
11510    }
11511
11512    pub fn convert_to_kebab_case(
11513        &mut self,
11514        _: &ConvertToKebabCase,
11515        window: &mut Window,
11516        cx: &mut Context<Self>,
11517    ) {
11518        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
11519    }
11520
11521    pub fn convert_to_upper_camel_case(
11522        &mut self,
11523        _: &ConvertToUpperCamelCase,
11524        window: &mut Window,
11525        cx: &mut Context<Self>,
11526    ) {
11527        self.manipulate_text(window, cx, |text| {
11528            text.split('\n')
11529                .map(|line| line.to_case(Case::UpperCamel))
11530                .join("\n")
11531        })
11532    }
11533
11534    pub fn convert_to_lower_camel_case(
11535        &mut self,
11536        _: &ConvertToLowerCamelCase,
11537        window: &mut Window,
11538        cx: &mut Context<Self>,
11539    ) {
11540        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
11541    }
11542
11543    pub fn convert_to_opposite_case(
11544        &mut self,
11545        _: &ConvertToOppositeCase,
11546        window: &mut Window,
11547        cx: &mut Context<Self>,
11548    ) {
11549        self.manipulate_text(window, cx, |text| {
11550            text.chars()
11551                .fold(String::with_capacity(text.len()), |mut t, c| {
11552                    if c.is_uppercase() {
11553                        t.extend(c.to_lowercase());
11554                    } else {
11555                        t.extend(c.to_uppercase());
11556                    }
11557                    t
11558                })
11559        })
11560    }
11561
11562    pub fn convert_to_sentence_case(
11563        &mut self,
11564        _: &ConvertToSentenceCase,
11565        window: &mut Window,
11566        cx: &mut Context<Self>,
11567    ) {
11568        self.manipulate_text(window, cx, |text| text.to_case(Case::Sentence))
11569    }
11570
11571    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
11572        self.manipulate_text(window, cx, |text| {
11573            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
11574            if has_upper_case_characters {
11575                text.to_lowercase()
11576            } else {
11577                text.to_uppercase()
11578            }
11579        })
11580    }
11581
11582    pub fn convert_to_rot13(
11583        &mut self,
11584        _: &ConvertToRot13,
11585        window: &mut Window,
11586        cx: &mut Context<Self>,
11587    ) {
11588        self.manipulate_text(window, cx, |text| {
11589            text.chars()
11590                .map(|c| match c {
11591                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
11592                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
11593                    _ => c,
11594                })
11595                .collect()
11596        })
11597    }
11598
11599    pub fn convert_to_rot47(
11600        &mut self,
11601        _: &ConvertToRot47,
11602        window: &mut Window,
11603        cx: &mut Context<Self>,
11604    ) {
11605        self.manipulate_text(window, cx, |text| {
11606            text.chars()
11607                .map(|c| {
11608                    let code_point = c as u32;
11609                    if code_point >= 33 && code_point <= 126 {
11610                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
11611                    }
11612                    c
11613                })
11614                .collect()
11615        })
11616    }
11617
11618    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
11619    where
11620        Fn: FnMut(&str) -> String,
11621    {
11622        let buffer = self.buffer.read(cx).snapshot(cx);
11623
11624        let mut new_selections = Vec::new();
11625        let mut edits = Vec::new();
11626        let mut selection_adjustment = 0i32;
11627
11628        for selection in self.selections.all_adjusted(&self.display_snapshot(cx)) {
11629            let selection_is_empty = selection.is_empty();
11630
11631            let (start, end) = if selection_is_empty {
11632                let (word_range, _) = buffer.surrounding_word(selection.start, None);
11633                (word_range.start, word_range.end)
11634            } else {
11635                (
11636                    buffer.point_to_offset(selection.start),
11637                    buffer.point_to_offset(selection.end),
11638                )
11639            };
11640
11641            let text = buffer.text_for_range(start..end).collect::<String>();
11642            let old_length = text.len() as i32;
11643            let text = callback(&text);
11644
11645            new_selections.push(Selection {
11646                start: (start as i32 - selection_adjustment) as usize,
11647                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
11648                goal: SelectionGoal::None,
11649                id: selection.id,
11650                reversed: selection.reversed,
11651            });
11652
11653            selection_adjustment += old_length - text.len() as i32;
11654
11655            edits.push((start..end, text));
11656        }
11657
11658        self.transact(window, cx, |this, window, cx| {
11659            this.buffer.update(cx, |buffer, cx| {
11660                buffer.edit(edits, None, cx);
11661            });
11662
11663            this.change_selections(Default::default(), window, cx, |s| {
11664                s.select(new_selections);
11665            });
11666
11667            this.request_autoscroll(Autoscroll::fit(), cx);
11668        });
11669    }
11670
11671    pub fn move_selection_on_drop(
11672        &mut self,
11673        selection: &Selection<Anchor>,
11674        target: DisplayPoint,
11675        is_cut: bool,
11676        window: &mut Window,
11677        cx: &mut Context<Self>,
11678    ) {
11679        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11680        let buffer = display_map.buffer_snapshot();
11681        let mut edits = Vec::new();
11682        let insert_point = display_map
11683            .clip_point(target, Bias::Left)
11684            .to_point(&display_map);
11685        let text = buffer
11686            .text_for_range(selection.start..selection.end)
11687            .collect::<String>();
11688        if is_cut {
11689            edits.push(((selection.start..selection.end), String::new()));
11690        }
11691        let insert_anchor = buffer.anchor_before(insert_point);
11692        edits.push(((insert_anchor..insert_anchor), text));
11693        let last_edit_start = insert_anchor.bias_left(buffer);
11694        let last_edit_end = insert_anchor.bias_right(buffer);
11695        self.transact(window, cx, |this, window, cx| {
11696            this.buffer.update(cx, |buffer, cx| {
11697                buffer.edit(edits, None, cx);
11698            });
11699            this.change_selections(Default::default(), window, cx, |s| {
11700                s.select_anchor_ranges([last_edit_start..last_edit_end]);
11701            });
11702        });
11703    }
11704
11705    pub fn clear_selection_drag_state(&mut self) {
11706        self.selection_drag_state = SelectionDragState::None;
11707    }
11708
11709    pub fn duplicate(
11710        &mut self,
11711        upwards: bool,
11712        whole_lines: bool,
11713        window: &mut Window,
11714        cx: &mut Context<Self>,
11715    ) {
11716        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11717
11718        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11719        let buffer = display_map.buffer_snapshot();
11720        let selections = self.selections.all::<Point>(&display_map);
11721
11722        let mut edits = Vec::new();
11723        let mut selections_iter = selections.iter().peekable();
11724        while let Some(selection) = selections_iter.next() {
11725            let mut rows = selection.spanned_rows(false, &display_map);
11726            // duplicate line-wise
11727            if whole_lines || selection.start == selection.end {
11728                // Avoid duplicating the same lines twice.
11729                while let Some(next_selection) = selections_iter.peek() {
11730                    let next_rows = next_selection.spanned_rows(false, &display_map);
11731                    if next_rows.start < rows.end {
11732                        rows.end = next_rows.end;
11733                        selections_iter.next().unwrap();
11734                    } else {
11735                        break;
11736                    }
11737                }
11738
11739                // Copy the text from the selected row region and splice it either at the start
11740                // or end of the region.
11741                let start = Point::new(rows.start.0, 0);
11742                let end = Point::new(
11743                    rows.end.previous_row().0,
11744                    buffer.line_len(rows.end.previous_row()),
11745                );
11746
11747                let mut text = buffer.text_for_range(start..end).collect::<String>();
11748
11749                let insert_location = if upwards {
11750                    // When duplicating upward, we need to insert before the current line.
11751                    // If we're on the last line and it doesn't end with a newline,
11752                    // we need to add a newline before the duplicated content.
11753                    let needs_leading_newline = rows.end.0 >= buffer.max_point().row
11754                        && buffer.max_point().column > 0
11755                        && !text.ends_with('\n');
11756
11757                    if needs_leading_newline {
11758                        text.insert(0, '\n');
11759                        end
11760                    } else {
11761                        text.push('\n');
11762                        Point::new(rows.start.0, 0)
11763                    }
11764                } else {
11765                    text.push('\n');
11766                    start
11767                };
11768                edits.push((insert_location..insert_location, text));
11769            } else {
11770                // duplicate character-wise
11771                let start = selection.start;
11772                let end = selection.end;
11773                let text = buffer.text_for_range(start..end).collect::<String>();
11774                edits.push((selection.end..selection.end, text));
11775            }
11776        }
11777
11778        self.transact(window, cx, |this, window, cx| {
11779            this.buffer.update(cx, |buffer, cx| {
11780                buffer.edit(edits, None, cx);
11781            });
11782
11783            // When duplicating upward with whole lines, move the cursor to the duplicated line
11784            if upwards && whole_lines {
11785                let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
11786
11787                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
11788                    let mut new_ranges = Vec::new();
11789                    let selections = s.all::<Point>(&display_map);
11790                    let mut selections_iter = selections.iter().peekable();
11791
11792                    while let Some(first_selection) = selections_iter.next() {
11793                        // Group contiguous selections together to find the total row span
11794                        let mut group_selections = vec![first_selection];
11795                        let mut rows = first_selection.spanned_rows(false, &display_map);
11796
11797                        while let Some(next_selection) = selections_iter.peek() {
11798                            let next_rows = next_selection.spanned_rows(false, &display_map);
11799                            if next_rows.start < rows.end {
11800                                rows.end = next_rows.end;
11801                                group_selections.push(selections_iter.next().unwrap());
11802                            } else {
11803                                break;
11804                            }
11805                        }
11806
11807                        let row_count = rows.end.0 - rows.start.0;
11808
11809                        // Move all selections in this group up by the total number of duplicated rows
11810                        for selection in group_selections {
11811                            let new_start = Point::new(
11812                                selection.start.row.saturating_sub(row_count),
11813                                selection.start.column,
11814                            );
11815
11816                            let new_end = Point::new(
11817                                selection.end.row.saturating_sub(row_count),
11818                                selection.end.column,
11819                            );
11820
11821                            new_ranges.push(new_start..new_end);
11822                        }
11823                    }
11824
11825                    s.select_ranges(new_ranges);
11826                });
11827            }
11828
11829            this.request_autoscroll(Autoscroll::fit(), cx);
11830        });
11831    }
11832
11833    pub fn duplicate_line_up(
11834        &mut self,
11835        _: &DuplicateLineUp,
11836        window: &mut Window,
11837        cx: &mut Context<Self>,
11838    ) {
11839        self.duplicate(true, true, window, cx);
11840    }
11841
11842    pub fn duplicate_line_down(
11843        &mut self,
11844        _: &DuplicateLineDown,
11845        window: &mut Window,
11846        cx: &mut Context<Self>,
11847    ) {
11848        self.duplicate(false, true, window, cx);
11849    }
11850
11851    pub fn duplicate_selection(
11852        &mut self,
11853        _: &DuplicateSelection,
11854        window: &mut Window,
11855        cx: &mut Context<Self>,
11856    ) {
11857        self.duplicate(false, false, window, cx);
11858    }
11859
11860    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
11861        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11862        if self.mode.is_single_line() {
11863            cx.propagate();
11864            return;
11865        }
11866
11867        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11868        let buffer = self.buffer.read(cx).snapshot(cx);
11869
11870        let mut edits = Vec::new();
11871        let mut unfold_ranges = Vec::new();
11872        let mut refold_creases = Vec::new();
11873
11874        let selections = self.selections.all::<Point>(&display_map);
11875        let mut selections = selections.iter().peekable();
11876        let mut contiguous_row_selections = Vec::new();
11877        let mut new_selections = Vec::new();
11878
11879        while let Some(selection) = selections.next() {
11880            // Find all the selections that span a contiguous row range
11881            let (start_row, end_row) = consume_contiguous_rows(
11882                &mut contiguous_row_selections,
11883                selection,
11884                &display_map,
11885                &mut selections,
11886            );
11887
11888            // Move the text spanned by the row range to be before the line preceding the row range
11889            if start_row.0 > 0 {
11890                let range_to_move = Point::new(
11891                    start_row.previous_row().0,
11892                    buffer.line_len(start_row.previous_row()),
11893                )
11894                    ..Point::new(
11895                        end_row.previous_row().0,
11896                        buffer.line_len(end_row.previous_row()),
11897                    );
11898                let insertion_point = display_map
11899                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
11900                    .0;
11901
11902                // Don't move lines across excerpts
11903                if buffer
11904                    .excerpt_containing(insertion_point..range_to_move.end)
11905                    .is_some()
11906                {
11907                    let text = buffer
11908                        .text_for_range(range_to_move.clone())
11909                        .flat_map(|s| s.chars())
11910                        .skip(1)
11911                        .chain(['\n'])
11912                        .collect::<String>();
11913
11914                    edits.push((
11915                        buffer.anchor_after(range_to_move.start)
11916                            ..buffer.anchor_before(range_to_move.end),
11917                        String::new(),
11918                    ));
11919                    let insertion_anchor = buffer.anchor_after(insertion_point);
11920                    edits.push((insertion_anchor..insertion_anchor, text));
11921
11922                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
11923
11924                    // Move selections up
11925                    new_selections.extend(contiguous_row_selections.drain(..).map(
11926                        |mut selection| {
11927                            selection.start.row -= row_delta;
11928                            selection.end.row -= row_delta;
11929                            selection
11930                        },
11931                    ));
11932
11933                    // Move folds up
11934                    unfold_ranges.push(range_to_move.clone());
11935                    for fold in display_map.folds_in_range(
11936                        buffer.anchor_before(range_to_move.start)
11937                            ..buffer.anchor_after(range_to_move.end),
11938                    ) {
11939                        let mut start = fold.range.start.to_point(&buffer);
11940                        let mut end = fold.range.end.to_point(&buffer);
11941                        start.row -= row_delta;
11942                        end.row -= row_delta;
11943                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11944                    }
11945                }
11946            }
11947
11948            // If we didn't move line(s), preserve the existing selections
11949            new_selections.append(&mut contiguous_row_selections);
11950        }
11951
11952        self.transact(window, cx, |this, window, cx| {
11953            this.unfold_ranges(&unfold_ranges, true, true, cx);
11954            this.buffer.update(cx, |buffer, cx| {
11955                for (range, text) in edits {
11956                    buffer.edit([(range, text)], None, cx);
11957                }
11958            });
11959            this.fold_creases(refold_creases, true, window, cx);
11960            this.change_selections(Default::default(), window, cx, |s| {
11961                s.select(new_selections);
11962            })
11963        });
11964    }
11965
11966    pub fn move_line_down(
11967        &mut self,
11968        _: &MoveLineDown,
11969        window: &mut Window,
11970        cx: &mut Context<Self>,
11971    ) {
11972        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11973        if self.mode.is_single_line() {
11974            cx.propagate();
11975            return;
11976        }
11977
11978        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11979        let buffer = self.buffer.read(cx).snapshot(cx);
11980
11981        let mut edits = Vec::new();
11982        let mut unfold_ranges = Vec::new();
11983        let mut refold_creases = Vec::new();
11984
11985        let selections = self.selections.all::<Point>(&display_map);
11986        let mut selections = selections.iter().peekable();
11987        let mut contiguous_row_selections = Vec::new();
11988        let mut new_selections = Vec::new();
11989
11990        while let Some(selection) = selections.next() {
11991            // Find all the selections that span a contiguous row range
11992            let (start_row, end_row) = consume_contiguous_rows(
11993                &mut contiguous_row_selections,
11994                selection,
11995                &display_map,
11996                &mut selections,
11997            );
11998
11999            // Move the text spanned by the row range to be after the last line of the row range
12000            if end_row.0 <= buffer.max_point().row {
12001                let range_to_move =
12002                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
12003                let insertion_point = display_map
12004                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
12005                    .0;
12006
12007                // Don't move lines across excerpt boundaries
12008                if buffer
12009                    .excerpt_containing(range_to_move.start..insertion_point)
12010                    .is_some()
12011                {
12012                    let mut text = String::from("\n");
12013                    text.extend(buffer.text_for_range(range_to_move.clone()));
12014                    text.pop(); // Drop trailing newline
12015                    edits.push((
12016                        buffer.anchor_after(range_to_move.start)
12017                            ..buffer.anchor_before(range_to_move.end),
12018                        String::new(),
12019                    ));
12020                    let insertion_anchor = buffer.anchor_after(insertion_point);
12021                    edits.push((insertion_anchor..insertion_anchor, text));
12022
12023                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
12024
12025                    // Move selections down
12026                    new_selections.extend(contiguous_row_selections.drain(..).map(
12027                        |mut selection| {
12028                            selection.start.row += row_delta;
12029                            selection.end.row += row_delta;
12030                            selection
12031                        },
12032                    ));
12033
12034                    // Move folds down
12035                    unfold_ranges.push(range_to_move.clone());
12036                    for fold in display_map.folds_in_range(
12037                        buffer.anchor_before(range_to_move.start)
12038                            ..buffer.anchor_after(range_to_move.end),
12039                    ) {
12040                        let mut start = fold.range.start.to_point(&buffer);
12041                        let mut end = fold.range.end.to_point(&buffer);
12042                        start.row += row_delta;
12043                        end.row += row_delta;
12044                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
12045                    }
12046                }
12047            }
12048
12049            // If we didn't move line(s), preserve the existing selections
12050            new_selections.append(&mut contiguous_row_selections);
12051        }
12052
12053        self.transact(window, cx, |this, window, cx| {
12054            this.unfold_ranges(&unfold_ranges, true, true, cx);
12055            this.buffer.update(cx, |buffer, cx| {
12056                for (range, text) in edits {
12057                    buffer.edit([(range, text)], None, cx);
12058                }
12059            });
12060            this.fold_creases(refold_creases, true, window, cx);
12061            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
12062        });
12063    }
12064
12065    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
12066        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12067        let text_layout_details = &self.text_layout_details(window);
12068        self.transact(window, cx, |this, window, cx| {
12069            let edits = this.change_selections(Default::default(), window, cx, |s| {
12070                let mut edits: Vec<(Range<usize>, String)> = Default::default();
12071                s.move_with(|display_map, selection| {
12072                    if !selection.is_empty() {
12073                        return;
12074                    }
12075
12076                    let mut head = selection.head();
12077                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
12078                    if head.column() == display_map.line_len(head.row()) {
12079                        transpose_offset = display_map
12080                            .buffer_snapshot()
12081                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
12082                    }
12083
12084                    if transpose_offset == 0 {
12085                        return;
12086                    }
12087
12088                    *head.column_mut() += 1;
12089                    head = display_map.clip_point(head, Bias::Right);
12090                    let goal = SelectionGoal::HorizontalPosition(
12091                        display_map
12092                            .x_for_display_point(head, text_layout_details)
12093                            .into(),
12094                    );
12095                    selection.collapse_to(head, goal);
12096
12097                    let transpose_start = display_map
12098                        .buffer_snapshot()
12099                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
12100                    if edits.last().is_none_or(|e| e.0.end <= transpose_start) {
12101                        let transpose_end = display_map
12102                            .buffer_snapshot()
12103                            .clip_offset(transpose_offset + 1, Bias::Right);
12104                        if let Some(ch) = display_map
12105                            .buffer_snapshot()
12106                            .chars_at(transpose_start)
12107                            .next()
12108                        {
12109                            edits.push((transpose_start..transpose_offset, String::new()));
12110                            edits.push((transpose_end..transpose_end, ch.to_string()));
12111                        }
12112                    }
12113                });
12114                edits
12115            });
12116            this.buffer
12117                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12118            let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
12119            this.change_selections(Default::default(), window, cx, |s| {
12120                s.select(selections);
12121            });
12122        });
12123    }
12124
12125    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
12126        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12127        if self.mode.is_single_line() {
12128            cx.propagate();
12129            return;
12130        }
12131
12132        self.rewrap_impl(RewrapOptions::default(), cx)
12133    }
12134
12135    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
12136        let buffer = self.buffer.read(cx).snapshot(cx);
12137        let selections = self.selections.all::<Point>(&self.display_snapshot(cx));
12138
12139        #[derive(Clone, Debug, PartialEq)]
12140        enum CommentFormat {
12141            /// single line comment, with prefix for line
12142            Line(String),
12143            /// single line within a block comment, with prefix for line
12144            BlockLine(String),
12145            /// a single line of a block comment that includes the initial delimiter
12146            BlockCommentWithStart(BlockCommentConfig),
12147            /// a single line of a block comment that includes the ending delimiter
12148            BlockCommentWithEnd(BlockCommentConfig),
12149        }
12150
12151        // Split selections to respect paragraph, indent, and comment prefix boundaries.
12152        let wrap_ranges = selections.into_iter().flat_map(|selection| {
12153            let mut non_blank_rows_iter = (selection.start.row..=selection.end.row)
12154                .filter(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
12155                .peekable();
12156
12157            let first_row = if let Some(&row) = non_blank_rows_iter.peek() {
12158                row
12159            } else {
12160                return Vec::new();
12161            };
12162
12163            let language_settings = buffer.language_settings_at(selection.head(), cx);
12164            let language_scope = buffer.language_scope_at(selection.head());
12165
12166            let indent_and_prefix_for_row =
12167                |row: u32| -> (IndentSize, Option<CommentFormat>, Option<String>) {
12168                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
12169                    let (comment_prefix, rewrap_prefix) = if let Some(language_scope) =
12170                        &language_scope
12171                    {
12172                        let indent_end = Point::new(row, indent.len);
12173                        let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
12174                        let line_text_after_indent = buffer
12175                            .text_for_range(indent_end..line_end)
12176                            .collect::<String>();
12177
12178                        let is_within_comment_override = buffer
12179                            .language_scope_at(indent_end)
12180                            .is_some_and(|scope| scope.override_name() == Some("comment"));
12181                        let comment_delimiters = if is_within_comment_override {
12182                            // we are within a comment syntax node, but we don't
12183                            // yet know what kind of comment: block, doc or line
12184                            match (
12185                                language_scope.documentation_comment(),
12186                                language_scope.block_comment(),
12187                            ) {
12188                                (Some(config), _) | (_, Some(config))
12189                                    if buffer.contains_str_at(indent_end, &config.start) =>
12190                                {
12191                                    Some(CommentFormat::BlockCommentWithStart(config.clone()))
12192                                }
12193                                (Some(config), _) | (_, Some(config))
12194                                    if line_text_after_indent.ends_with(config.end.as_ref()) =>
12195                                {
12196                                    Some(CommentFormat::BlockCommentWithEnd(config.clone()))
12197                                }
12198                                (Some(config), _) | (_, Some(config))
12199                                    if buffer.contains_str_at(indent_end, &config.prefix) =>
12200                                {
12201                                    Some(CommentFormat::BlockLine(config.prefix.to_string()))
12202                                }
12203                                (_, _) => language_scope
12204                                    .line_comment_prefixes()
12205                                    .iter()
12206                                    .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12207                                    .map(|prefix| CommentFormat::Line(prefix.to_string())),
12208                            }
12209                        } else {
12210                            // we not in an overridden comment node, but we may
12211                            // be within a non-overridden line comment node
12212                            language_scope
12213                                .line_comment_prefixes()
12214                                .iter()
12215                                .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12216                                .map(|prefix| CommentFormat::Line(prefix.to_string()))
12217                        };
12218
12219                        let rewrap_prefix = language_scope
12220                            .rewrap_prefixes()
12221                            .iter()
12222                            .find_map(|prefix_regex| {
12223                                prefix_regex.find(&line_text_after_indent).map(|mat| {
12224                                    if mat.start() == 0 {
12225                                        Some(mat.as_str().to_string())
12226                                    } else {
12227                                        None
12228                                    }
12229                                })
12230                            })
12231                            .flatten();
12232                        (comment_delimiters, rewrap_prefix)
12233                    } else {
12234                        (None, None)
12235                    };
12236                    (indent, comment_prefix, rewrap_prefix)
12237                };
12238
12239            let mut ranges = Vec::new();
12240            let from_empty_selection = selection.is_empty();
12241
12242            let mut current_range_start = first_row;
12243            let mut prev_row = first_row;
12244            let (
12245                mut current_range_indent,
12246                mut current_range_comment_delimiters,
12247                mut current_range_rewrap_prefix,
12248            ) = indent_and_prefix_for_row(first_row);
12249
12250            for row in non_blank_rows_iter.skip(1) {
12251                let has_paragraph_break = row > prev_row + 1;
12252
12253                let (row_indent, row_comment_delimiters, row_rewrap_prefix) =
12254                    indent_and_prefix_for_row(row);
12255
12256                let has_indent_change = row_indent != current_range_indent;
12257                let has_comment_change = row_comment_delimiters != current_range_comment_delimiters;
12258
12259                let has_boundary_change = has_comment_change
12260                    || row_rewrap_prefix.is_some()
12261                    || (has_indent_change && current_range_comment_delimiters.is_some());
12262
12263                if has_paragraph_break || has_boundary_change {
12264                    ranges.push((
12265                        language_settings.clone(),
12266                        Point::new(current_range_start, 0)
12267                            ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12268                        current_range_indent,
12269                        current_range_comment_delimiters.clone(),
12270                        current_range_rewrap_prefix.clone(),
12271                        from_empty_selection,
12272                    ));
12273                    current_range_start = row;
12274                    current_range_indent = row_indent;
12275                    current_range_comment_delimiters = row_comment_delimiters;
12276                    current_range_rewrap_prefix = row_rewrap_prefix;
12277                }
12278                prev_row = row;
12279            }
12280
12281            ranges.push((
12282                language_settings.clone(),
12283                Point::new(current_range_start, 0)
12284                    ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12285                current_range_indent,
12286                current_range_comment_delimiters,
12287                current_range_rewrap_prefix,
12288                from_empty_selection,
12289            ));
12290
12291            ranges
12292        });
12293
12294        let mut edits = Vec::new();
12295        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
12296
12297        for (
12298            language_settings,
12299            wrap_range,
12300            mut indent_size,
12301            comment_prefix,
12302            rewrap_prefix,
12303            from_empty_selection,
12304        ) in wrap_ranges
12305        {
12306            let mut start_row = wrap_range.start.row;
12307            let mut end_row = wrap_range.end.row;
12308
12309            // Skip selections that overlap with a range that has already been rewrapped.
12310            let selection_range = start_row..end_row;
12311            if rewrapped_row_ranges
12312                .iter()
12313                .any(|range| range.overlaps(&selection_range))
12314            {
12315                continue;
12316            }
12317
12318            let tab_size = language_settings.tab_size;
12319
12320            let (line_prefix, inside_comment) = match &comment_prefix {
12321                Some(CommentFormat::Line(prefix) | CommentFormat::BlockLine(prefix)) => {
12322                    (Some(prefix.as_str()), true)
12323                }
12324                Some(CommentFormat::BlockCommentWithEnd(BlockCommentConfig { prefix, .. })) => {
12325                    (Some(prefix.as_ref()), true)
12326                }
12327                Some(CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12328                    start: _,
12329                    end: _,
12330                    prefix,
12331                    tab_size,
12332                })) => {
12333                    indent_size.len += tab_size;
12334                    (Some(prefix.as_ref()), true)
12335                }
12336                None => (None, false),
12337            };
12338            let indent_prefix = indent_size.chars().collect::<String>();
12339            let line_prefix = format!("{indent_prefix}{}", line_prefix.unwrap_or(""));
12340
12341            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
12342                RewrapBehavior::InComments => inside_comment,
12343                RewrapBehavior::InSelections => !wrap_range.is_empty(),
12344                RewrapBehavior::Anywhere => true,
12345            };
12346
12347            let should_rewrap = options.override_language_settings
12348                || allow_rewrap_based_on_language
12349                || self.hard_wrap.is_some();
12350            if !should_rewrap {
12351                continue;
12352            }
12353
12354            if from_empty_selection {
12355                'expand_upwards: while start_row > 0 {
12356                    let prev_row = start_row - 1;
12357                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
12358                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
12359                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
12360                    {
12361                        start_row = prev_row;
12362                    } else {
12363                        break 'expand_upwards;
12364                    }
12365                }
12366
12367                'expand_downwards: while end_row < buffer.max_point().row {
12368                    let next_row = end_row + 1;
12369                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
12370                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
12371                        && !buffer.is_line_blank(MultiBufferRow(next_row))
12372                    {
12373                        end_row = next_row;
12374                    } else {
12375                        break 'expand_downwards;
12376                    }
12377                }
12378            }
12379
12380            let start = Point::new(start_row, 0);
12381            let start_offset = ToOffset::to_offset(&start, &buffer);
12382            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
12383            let selection_text = buffer.text_for_range(start..end).collect::<String>();
12384            let mut first_line_delimiter = None;
12385            let mut last_line_delimiter = None;
12386            let Some(lines_without_prefixes) = selection_text
12387                .lines()
12388                .enumerate()
12389                .map(|(ix, line)| {
12390                    let line_trimmed = line.trim_start();
12391                    if rewrap_prefix.is_some() && ix > 0 {
12392                        Ok(line_trimmed)
12393                    } else if let Some(
12394                        CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12395                            start,
12396                            prefix,
12397                            end,
12398                            tab_size,
12399                        })
12400                        | CommentFormat::BlockCommentWithEnd(BlockCommentConfig {
12401                            start,
12402                            prefix,
12403                            end,
12404                            tab_size,
12405                        }),
12406                    ) = &comment_prefix
12407                    {
12408                        let line_trimmed = line_trimmed
12409                            .strip_prefix(start.as_ref())
12410                            .map(|s| {
12411                                let mut indent_size = indent_size;
12412                                indent_size.len -= tab_size;
12413                                let indent_prefix: String = indent_size.chars().collect();
12414                                first_line_delimiter = Some((indent_prefix, start));
12415                                s.trim_start()
12416                            })
12417                            .unwrap_or(line_trimmed);
12418                        let line_trimmed = line_trimmed
12419                            .strip_suffix(end.as_ref())
12420                            .map(|s| {
12421                                last_line_delimiter = Some(end);
12422                                s.trim_end()
12423                            })
12424                            .unwrap_or(line_trimmed);
12425                        let line_trimmed = line_trimmed
12426                            .strip_prefix(prefix.as_ref())
12427                            .unwrap_or(line_trimmed);
12428                        Ok(line_trimmed)
12429                    } else if let Some(CommentFormat::BlockLine(prefix)) = &comment_prefix {
12430                        line_trimmed.strip_prefix(prefix).with_context(|| {
12431                            format!("line did not start with prefix {prefix:?}: {line:?}")
12432                        })
12433                    } else {
12434                        line_trimmed
12435                            .strip_prefix(&line_prefix.trim_start())
12436                            .with_context(|| {
12437                                format!("line did not start with prefix {line_prefix:?}: {line:?}")
12438                            })
12439                    }
12440                })
12441                .collect::<Result<Vec<_>, _>>()
12442                .log_err()
12443            else {
12444                continue;
12445            };
12446
12447            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
12448                buffer
12449                    .language_settings_at(Point::new(start_row, 0), cx)
12450                    .preferred_line_length as usize
12451            });
12452
12453            let subsequent_lines_prefix = if let Some(rewrap_prefix_str) = &rewrap_prefix {
12454                format!("{}{}", indent_prefix, " ".repeat(rewrap_prefix_str.len()))
12455            } else {
12456                line_prefix.clone()
12457            };
12458
12459            let wrapped_text = {
12460                let mut wrapped_text = wrap_with_prefix(
12461                    line_prefix,
12462                    subsequent_lines_prefix,
12463                    lines_without_prefixes.join("\n"),
12464                    wrap_column,
12465                    tab_size,
12466                    options.preserve_existing_whitespace,
12467                );
12468
12469                if let Some((indent, delimiter)) = first_line_delimiter {
12470                    wrapped_text = format!("{indent}{delimiter}\n{wrapped_text}");
12471                }
12472                if let Some(last_line) = last_line_delimiter {
12473                    wrapped_text = format!("{wrapped_text}\n{indent_prefix}{last_line}");
12474                }
12475
12476                wrapped_text
12477            };
12478
12479            // TODO: should always use char-based diff while still supporting cursor behavior that
12480            // matches vim.
12481            let mut diff_options = DiffOptions::default();
12482            if options.override_language_settings {
12483                diff_options.max_word_diff_len = 0;
12484                diff_options.max_word_diff_line_count = 0;
12485            } else {
12486                diff_options.max_word_diff_len = usize::MAX;
12487                diff_options.max_word_diff_line_count = usize::MAX;
12488            }
12489
12490            for (old_range, new_text) in
12491                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
12492            {
12493                let edit_start = buffer.anchor_after(start_offset + old_range.start);
12494                let edit_end = buffer.anchor_after(start_offset + old_range.end);
12495                edits.push((edit_start..edit_end, new_text));
12496            }
12497
12498            rewrapped_row_ranges.push(start_row..=end_row);
12499        }
12500
12501        self.buffer
12502            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12503    }
12504
12505    pub fn cut_common(
12506        &mut self,
12507        cut_no_selection_line: bool,
12508        window: &mut Window,
12509        cx: &mut Context<Self>,
12510    ) -> ClipboardItem {
12511        let mut text = String::new();
12512        let buffer = self.buffer.read(cx).snapshot(cx);
12513        let mut selections = self.selections.all::<Point>(&self.display_snapshot(cx));
12514        let mut clipboard_selections = Vec::with_capacity(selections.len());
12515        {
12516            let max_point = buffer.max_point();
12517            let mut is_first = true;
12518            for selection in &mut selections {
12519                let is_entire_line =
12520                    (selection.is_empty() && cut_no_selection_line) || self.selections.line_mode();
12521                if is_entire_line {
12522                    selection.start = Point::new(selection.start.row, 0);
12523                    if !selection.is_empty() && selection.end.column == 0 {
12524                        selection.end = cmp::min(max_point, selection.end);
12525                    } else {
12526                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
12527                    }
12528                    selection.goal = SelectionGoal::None;
12529                }
12530                if is_first {
12531                    is_first = false;
12532                } else {
12533                    text += "\n";
12534                }
12535                let mut len = 0;
12536                for chunk in buffer.text_for_range(selection.start..selection.end) {
12537                    text.push_str(chunk);
12538                    len += chunk.len();
12539                }
12540                clipboard_selections.push(ClipboardSelection {
12541                    len,
12542                    is_entire_line,
12543                    first_line_indent: buffer
12544                        .indent_size_for_line(MultiBufferRow(selection.start.row))
12545                        .len,
12546                });
12547            }
12548        }
12549
12550        self.transact(window, cx, |this, window, cx| {
12551            this.change_selections(Default::default(), window, cx, |s| {
12552                s.select(selections);
12553            });
12554            this.insert("", window, cx);
12555        });
12556        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
12557    }
12558
12559    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
12560        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12561        let item = self.cut_common(true, window, cx);
12562        cx.write_to_clipboard(item);
12563    }
12564
12565    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
12566        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12567        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12568            s.move_with(|snapshot, sel| {
12569                if sel.is_empty() {
12570                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()));
12571                }
12572                if sel.is_empty() {
12573                    sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
12574                }
12575            });
12576        });
12577        let item = self.cut_common(false, window, cx);
12578        cx.set_global(KillRing(item))
12579    }
12580
12581    pub fn kill_ring_yank(
12582        &mut self,
12583        _: &KillRingYank,
12584        window: &mut Window,
12585        cx: &mut Context<Self>,
12586    ) {
12587        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12588        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
12589            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
12590                (kill_ring.text().to_string(), kill_ring.metadata_json())
12591            } else {
12592                return;
12593            }
12594        } else {
12595            return;
12596        };
12597        self.do_paste(&text, metadata, false, window, cx);
12598    }
12599
12600    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
12601        self.do_copy(true, cx);
12602    }
12603
12604    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
12605        self.do_copy(false, cx);
12606    }
12607
12608    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
12609        let selections = self.selections.all::<Point>(&self.display_snapshot(cx));
12610        let buffer = self.buffer.read(cx).read(cx);
12611        let mut text = String::new();
12612
12613        let mut clipboard_selections = Vec::with_capacity(selections.len());
12614        {
12615            let max_point = buffer.max_point();
12616            let mut is_first = true;
12617            for selection in &selections {
12618                let mut start = selection.start;
12619                let mut end = selection.end;
12620                let is_entire_line = selection.is_empty() || self.selections.line_mode();
12621                let mut add_trailing_newline = false;
12622                if is_entire_line {
12623                    start = Point::new(start.row, 0);
12624                    let next_line_start = Point::new(end.row + 1, 0);
12625                    if next_line_start <= max_point {
12626                        end = next_line_start;
12627                    } else {
12628                        // We're on the last line without a trailing newline.
12629                        // Copy to the end of the line and add a newline afterwards.
12630                        end = Point::new(end.row, buffer.line_len(MultiBufferRow(end.row)));
12631                        add_trailing_newline = true;
12632                    }
12633                }
12634
12635                let mut trimmed_selections = Vec::new();
12636                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
12637                    let row = MultiBufferRow(start.row);
12638                    let first_indent = buffer.indent_size_for_line(row);
12639                    if first_indent.len == 0 || start.column > first_indent.len {
12640                        trimmed_selections.push(start..end);
12641                    } else {
12642                        trimmed_selections.push(
12643                            Point::new(row.0, first_indent.len)
12644                                ..Point::new(row.0, buffer.line_len(row)),
12645                        );
12646                        for row in start.row + 1..=end.row {
12647                            let mut line_len = buffer.line_len(MultiBufferRow(row));
12648                            if row == end.row {
12649                                line_len = end.column;
12650                            }
12651                            if line_len == 0 {
12652                                trimmed_selections
12653                                    .push(Point::new(row, 0)..Point::new(row, line_len));
12654                                continue;
12655                            }
12656                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
12657                            if row_indent_size.len >= first_indent.len {
12658                                trimmed_selections.push(
12659                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
12660                                );
12661                            } else {
12662                                trimmed_selections.clear();
12663                                trimmed_selections.push(start..end);
12664                                break;
12665                            }
12666                        }
12667                    }
12668                } else {
12669                    trimmed_selections.push(start..end);
12670                }
12671
12672                for trimmed_range in trimmed_selections {
12673                    if is_first {
12674                        is_first = false;
12675                    } else {
12676                        text += "\n";
12677                    }
12678                    let mut len = 0;
12679                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
12680                        text.push_str(chunk);
12681                        len += chunk.len();
12682                    }
12683                    if add_trailing_newline {
12684                        text.push('\n');
12685                        len += 1;
12686                    }
12687                    clipboard_selections.push(ClipboardSelection {
12688                        len,
12689                        is_entire_line,
12690                        first_line_indent: buffer
12691                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
12692                            .len,
12693                    });
12694                }
12695            }
12696        }
12697
12698        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
12699            text,
12700            clipboard_selections,
12701        ));
12702    }
12703
12704    pub fn do_paste(
12705        &mut self,
12706        text: &String,
12707        clipboard_selections: Option<Vec<ClipboardSelection>>,
12708        handle_entire_lines: bool,
12709        window: &mut Window,
12710        cx: &mut Context<Self>,
12711    ) {
12712        if self.read_only(cx) {
12713            return;
12714        }
12715
12716        let clipboard_text = Cow::Borrowed(text.as_str());
12717
12718        self.transact(window, cx, |this, window, cx| {
12719            let had_active_edit_prediction = this.has_active_edit_prediction();
12720            let display_map = this.display_snapshot(cx);
12721            let old_selections = this.selections.all::<usize>(&display_map);
12722            let cursor_offset = this.selections.last::<usize>(&display_map).head();
12723
12724            if let Some(mut clipboard_selections) = clipboard_selections {
12725                let all_selections_were_entire_line =
12726                    clipboard_selections.iter().all(|s| s.is_entire_line);
12727                let first_selection_indent_column =
12728                    clipboard_selections.first().map(|s| s.first_line_indent);
12729                if clipboard_selections.len() != old_selections.len() {
12730                    clipboard_selections.drain(..);
12731                }
12732                let mut auto_indent_on_paste = true;
12733
12734                this.buffer.update(cx, |buffer, cx| {
12735                    let snapshot = buffer.read(cx);
12736                    auto_indent_on_paste = snapshot
12737                        .language_settings_at(cursor_offset, cx)
12738                        .auto_indent_on_paste;
12739
12740                    let mut start_offset = 0;
12741                    let mut edits = Vec::new();
12742                    let mut original_indent_columns = Vec::new();
12743                    for (ix, selection) in old_selections.iter().enumerate() {
12744                        let to_insert;
12745                        let entire_line;
12746                        let original_indent_column;
12747                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
12748                            let end_offset = start_offset + clipboard_selection.len;
12749                            to_insert = &clipboard_text[start_offset..end_offset];
12750                            entire_line = clipboard_selection.is_entire_line;
12751                            start_offset = end_offset + 1;
12752                            original_indent_column = Some(clipboard_selection.first_line_indent);
12753                        } else {
12754                            to_insert = &*clipboard_text;
12755                            entire_line = all_selections_were_entire_line;
12756                            original_indent_column = first_selection_indent_column
12757                        }
12758
12759                        let (range, to_insert) =
12760                            if selection.is_empty() && handle_entire_lines && entire_line {
12761                                // If the corresponding selection was empty when this slice of the
12762                                // clipboard text was written, then the entire line containing the
12763                                // selection was copied. If this selection is also currently empty,
12764                                // then paste the line before the current line of the buffer.
12765                                let column = selection.start.to_point(&snapshot).column as usize;
12766                                let line_start = selection.start - column;
12767                                (line_start..line_start, Cow::Borrowed(to_insert))
12768                            } else {
12769                                let language = snapshot.language_at(selection.head());
12770                                let range = selection.range();
12771                                if let Some(language) = language
12772                                    && language.name() == "Markdown".into()
12773                                {
12774                                    edit_for_markdown_paste(
12775                                        &snapshot,
12776                                        range,
12777                                        to_insert,
12778                                        url::Url::parse(to_insert).ok(),
12779                                    )
12780                                } else {
12781                                    (range, Cow::Borrowed(to_insert))
12782                                }
12783                            };
12784
12785                        edits.push((range, to_insert));
12786                        original_indent_columns.push(original_indent_column);
12787                    }
12788                    drop(snapshot);
12789
12790                    buffer.edit(
12791                        edits,
12792                        if auto_indent_on_paste {
12793                            Some(AutoindentMode::Block {
12794                                original_indent_columns,
12795                            })
12796                        } else {
12797                            None
12798                        },
12799                        cx,
12800                    );
12801                });
12802
12803                let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
12804                this.change_selections(Default::default(), window, cx, |s| s.select(selections));
12805            } else {
12806                let url = url::Url::parse(&clipboard_text).ok();
12807
12808                let auto_indent_mode = if !clipboard_text.is_empty() {
12809                    Some(AutoindentMode::Block {
12810                        original_indent_columns: Vec::new(),
12811                    })
12812                } else {
12813                    None
12814                };
12815
12816                let selection_anchors = this.buffer.update(cx, |buffer, cx| {
12817                    let snapshot = buffer.snapshot(cx);
12818
12819                    let anchors = old_selections
12820                        .iter()
12821                        .map(|s| {
12822                            let anchor = snapshot.anchor_after(s.head());
12823                            s.map(|_| anchor)
12824                        })
12825                        .collect::<Vec<_>>();
12826
12827                    let mut edits = Vec::new();
12828
12829                    for selection in old_selections.iter() {
12830                        let language = snapshot.language_at(selection.head());
12831                        let range = selection.range();
12832
12833                        let (edit_range, edit_text) = if let Some(language) = language
12834                            && language.name() == "Markdown".into()
12835                        {
12836                            edit_for_markdown_paste(&snapshot, range, &clipboard_text, url.clone())
12837                        } else {
12838                            (range, clipboard_text.clone())
12839                        };
12840
12841                        edits.push((edit_range, edit_text));
12842                    }
12843
12844                    drop(snapshot);
12845                    buffer.edit(edits, auto_indent_mode, cx);
12846
12847                    anchors
12848                });
12849
12850                this.change_selections(Default::default(), window, cx, |s| {
12851                    s.select_anchors(selection_anchors);
12852                });
12853            }
12854
12855            let trigger_in_words =
12856                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
12857
12858            this.trigger_completion_on_input(text, trigger_in_words, window, cx);
12859        });
12860    }
12861
12862    pub fn diff_clipboard_with_selection(
12863        &mut self,
12864        _: &DiffClipboardWithSelection,
12865        window: &mut Window,
12866        cx: &mut Context<Self>,
12867    ) {
12868        let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
12869
12870        if selections.is_empty() {
12871            log::warn!("There should always be at least one selection in Zed. This is a bug.");
12872            return;
12873        };
12874
12875        let clipboard_text = match cx.read_from_clipboard() {
12876            Some(item) => match item.entries().first() {
12877                Some(ClipboardEntry::String(text)) => Some(text.text().to_string()),
12878                _ => None,
12879            },
12880            None => None,
12881        };
12882
12883        let Some(clipboard_text) = clipboard_text else {
12884            log::warn!("Clipboard doesn't contain text.");
12885            return;
12886        };
12887
12888        window.dispatch_action(
12889            Box::new(DiffClipboardWithSelectionData {
12890                clipboard_text,
12891                editor: cx.entity(),
12892            }),
12893            cx,
12894        );
12895    }
12896
12897    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
12898        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12899        if let Some(item) = cx.read_from_clipboard() {
12900            let entries = item.entries();
12901
12902            match entries.first() {
12903                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
12904                // of all the pasted entries.
12905                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
12906                    .do_paste(
12907                        clipboard_string.text(),
12908                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
12909                        true,
12910                        window,
12911                        cx,
12912                    ),
12913                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
12914            }
12915        }
12916    }
12917
12918    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
12919        if self.read_only(cx) {
12920            return;
12921        }
12922
12923        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12924
12925        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
12926            if let Some((selections, _)) =
12927                self.selection_history.transaction(transaction_id).cloned()
12928            {
12929                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12930                    s.select_anchors(selections.to_vec());
12931                });
12932            } else {
12933                log::error!(
12934                    "No entry in selection_history found for undo. \
12935                     This may correspond to a bug where undo does not update the selection. \
12936                     If this is occurring, please add details to \
12937                     https://github.com/zed-industries/zed/issues/22692"
12938                );
12939            }
12940            self.request_autoscroll(Autoscroll::fit(), cx);
12941            self.unmark_text(window, cx);
12942            self.refresh_edit_prediction(true, false, window, cx);
12943            cx.emit(EditorEvent::Edited { transaction_id });
12944            cx.emit(EditorEvent::TransactionUndone { transaction_id });
12945        }
12946    }
12947
12948    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
12949        if self.read_only(cx) {
12950            return;
12951        }
12952
12953        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12954
12955        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
12956            if let Some((_, Some(selections))) =
12957                self.selection_history.transaction(transaction_id).cloned()
12958            {
12959                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12960                    s.select_anchors(selections.to_vec());
12961                });
12962            } else {
12963                log::error!(
12964                    "No entry in selection_history found for redo. \
12965                     This may correspond to a bug where undo does not update the selection. \
12966                     If this is occurring, please add details to \
12967                     https://github.com/zed-industries/zed/issues/22692"
12968                );
12969            }
12970            self.request_autoscroll(Autoscroll::fit(), cx);
12971            self.unmark_text(window, cx);
12972            self.refresh_edit_prediction(true, false, window, cx);
12973            cx.emit(EditorEvent::Edited { transaction_id });
12974        }
12975    }
12976
12977    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
12978        self.buffer
12979            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
12980    }
12981
12982    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
12983        self.buffer
12984            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
12985    }
12986
12987    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
12988        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12989        self.change_selections(Default::default(), window, cx, |s| {
12990            s.move_with(|map, selection| {
12991                let cursor = if selection.is_empty() {
12992                    movement::left(map, selection.start)
12993                } else {
12994                    selection.start
12995                };
12996                selection.collapse_to(cursor, SelectionGoal::None);
12997            });
12998        })
12999    }
13000
13001    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
13002        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13003        self.change_selections(Default::default(), window, cx, |s| {
13004            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
13005        })
13006    }
13007
13008    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
13009        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13010        self.change_selections(Default::default(), window, cx, |s| {
13011            s.move_with(|map, selection| {
13012                let cursor = if selection.is_empty() {
13013                    movement::right(map, selection.end)
13014                } else {
13015                    selection.end
13016                };
13017                selection.collapse_to(cursor, SelectionGoal::None)
13018            });
13019        })
13020    }
13021
13022    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
13023        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13024        self.change_selections(Default::default(), window, cx, |s| {
13025            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
13026        });
13027    }
13028
13029    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
13030        if self.take_rename(true, window, cx).is_some() {
13031            return;
13032        }
13033
13034        if self.mode.is_single_line() {
13035            cx.propagate();
13036            return;
13037        }
13038
13039        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13040
13041        let text_layout_details = &self.text_layout_details(window);
13042        let selection_count = self.selections.count();
13043        let first_selection = self.selections.first_anchor();
13044
13045        self.change_selections(Default::default(), window, cx, |s| {
13046            s.move_with(|map, selection| {
13047                if !selection.is_empty() {
13048                    selection.goal = SelectionGoal::None;
13049                }
13050                let (cursor, goal) = movement::up(
13051                    map,
13052                    selection.start,
13053                    selection.goal,
13054                    false,
13055                    text_layout_details,
13056                );
13057                selection.collapse_to(cursor, goal);
13058            });
13059        });
13060
13061        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
13062        {
13063            cx.propagate();
13064        }
13065    }
13066
13067    pub fn move_up_by_lines(
13068        &mut self,
13069        action: &MoveUpByLines,
13070        window: &mut Window,
13071        cx: &mut Context<Self>,
13072    ) {
13073        if self.take_rename(true, window, cx).is_some() {
13074            return;
13075        }
13076
13077        if self.mode.is_single_line() {
13078            cx.propagate();
13079            return;
13080        }
13081
13082        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13083
13084        let text_layout_details = &self.text_layout_details(window);
13085
13086        self.change_selections(Default::default(), window, cx, |s| {
13087            s.move_with(|map, selection| {
13088                if !selection.is_empty() {
13089                    selection.goal = SelectionGoal::None;
13090                }
13091                let (cursor, goal) = movement::up_by_rows(
13092                    map,
13093                    selection.start,
13094                    action.lines,
13095                    selection.goal,
13096                    false,
13097                    text_layout_details,
13098                );
13099                selection.collapse_to(cursor, goal);
13100            });
13101        })
13102    }
13103
13104    pub fn move_down_by_lines(
13105        &mut self,
13106        action: &MoveDownByLines,
13107        window: &mut Window,
13108        cx: &mut Context<Self>,
13109    ) {
13110        if self.take_rename(true, window, cx).is_some() {
13111            return;
13112        }
13113
13114        if self.mode.is_single_line() {
13115            cx.propagate();
13116            return;
13117        }
13118
13119        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13120
13121        let text_layout_details = &self.text_layout_details(window);
13122
13123        self.change_selections(Default::default(), window, cx, |s| {
13124            s.move_with(|map, selection| {
13125                if !selection.is_empty() {
13126                    selection.goal = SelectionGoal::None;
13127                }
13128                let (cursor, goal) = movement::down_by_rows(
13129                    map,
13130                    selection.start,
13131                    action.lines,
13132                    selection.goal,
13133                    false,
13134                    text_layout_details,
13135                );
13136                selection.collapse_to(cursor, goal);
13137            });
13138        })
13139    }
13140
13141    pub fn select_down_by_lines(
13142        &mut self,
13143        action: &SelectDownByLines,
13144        window: &mut Window,
13145        cx: &mut Context<Self>,
13146    ) {
13147        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13148        let text_layout_details = &self.text_layout_details(window);
13149        self.change_selections(Default::default(), window, cx, |s| {
13150            s.move_heads_with(|map, head, goal| {
13151                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
13152            })
13153        })
13154    }
13155
13156    pub fn select_up_by_lines(
13157        &mut self,
13158        action: &SelectUpByLines,
13159        window: &mut Window,
13160        cx: &mut Context<Self>,
13161    ) {
13162        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13163        let text_layout_details = &self.text_layout_details(window);
13164        self.change_selections(Default::default(), window, cx, |s| {
13165            s.move_heads_with(|map, head, goal| {
13166                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
13167            })
13168        })
13169    }
13170
13171    pub fn select_page_up(
13172        &mut self,
13173        _: &SelectPageUp,
13174        window: &mut Window,
13175        cx: &mut Context<Self>,
13176    ) {
13177        let Some(row_count) = self.visible_row_count() else {
13178            return;
13179        };
13180
13181        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13182
13183        let text_layout_details = &self.text_layout_details(window);
13184
13185        self.change_selections(Default::default(), window, cx, |s| {
13186            s.move_heads_with(|map, head, goal| {
13187                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
13188            })
13189        })
13190    }
13191
13192    pub fn move_page_up(
13193        &mut self,
13194        action: &MovePageUp,
13195        window: &mut Window,
13196        cx: &mut Context<Self>,
13197    ) {
13198        if self.take_rename(true, window, cx).is_some() {
13199            return;
13200        }
13201
13202        if self
13203            .context_menu
13204            .borrow_mut()
13205            .as_mut()
13206            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
13207            .unwrap_or(false)
13208        {
13209            return;
13210        }
13211
13212        if matches!(self.mode, EditorMode::SingleLine) {
13213            cx.propagate();
13214            return;
13215        }
13216
13217        let Some(row_count) = self.visible_row_count() else {
13218            return;
13219        };
13220
13221        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13222
13223        let effects = if action.center_cursor {
13224            SelectionEffects::scroll(Autoscroll::center())
13225        } else {
13226            SelectionEffects::default()
13227        };
13228
13229        let text_layout_details = &self.text_layout_details(window);
13230
13231        self.change_selections(effects, window, cx, |s| {
13232            s.move_with(|map, selection| {
13233                if !selection.is_empty() {
13234                    selection.goal = SelectionGoal::None;
13235                }
13236                let (cursor, goal) = movement::up_by_rows(
13237                    map,
13238                    selection.end,
13239                    row_count,
13240                    selection.goal,
13241                    false,
13242                    text_layout_details,
13243                );
13244                selection.collapse_to(cursor, goal);
13245            });
13246        });
13247    }
13248
13249    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
13250        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13251        let text_layout_details = &self.text_layout_details(window);
13252        self.change_selections(Default::default(), window, cx, |s| {
13253            s.move_heads_with(|map, head, goal| {
13254                movement::up(map, head, goal, false, text_layout_details)
13255            })
13256        })
13257    }
13258
13259    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
13260        self.take_rename(true, window, cx);
13261
13262        if self.mode.is_single_line() {
13263            cx.propagate();
13264            return;
13265        }
13266
13267        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13268
13269        let text_layout_details = &self.text_layout_details(window);
13270        let selection_count = self.selections.count();
13271        let first_selection = self.selections.first_anchor();
13272
13273        self.change_selections(Default::default(), window, cx, |s| {
13274            s.move_with(|map, selection| {
13275                if !selection.is_empty() {
13276                    selection.goal = SelectionGoal::None;
13277                }
13278                let (cursor, goal) = movement::down(
13279                    map,
13280                    selection.end,
13281                    selection.goal,
13282                    false,
13283                    text_layout_details,
13284                );
13285                selection.collapse_to(cursor, goal);
13286            });
13287        });
13288
13289        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
13290        {
13291            cx.propagate();
13292        }
13293    }
13294
13295    pub fn select_page_down(
13296        &mut self,
13297        _: &SelectPageDown,
13298        window: &mut Window,
13299        cx: &mut Context<Self>,
13300    ) {
13301        let Some(row_count) = self.visible_row_count() else {
13302            return;
13303        };
13304
13305        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13306
13307        let text_layout_details = &self.text_layout_details(window);
13308
13309        self.change_selections(Default::default(), window, cx, |s| {
13310            s.move_heads_with(|map, head, goal| {
13311                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
13312            })
13313        })
13314    }
13315
13316    pub fn move_page_down(
13317        &mut self,
13318        action: &MovePageDown,
13319        window: &mut Window,
13320        cx: &mut Context<Self>,
13321    ) {
13322        if self.take_rename(true, window, cx).is_some() {
13323            return;
13324        }
13325
13326        if self
13327            .context_menu
13328            .borrow_mut()
13329            .as_mut()
13330            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
13331            .unwrap_or(false)
13332        {
13333            return;
13334        }
13335
13336        if matches!(self.mode, EditorMode::SingleLine) {
13337            cx.propagate();
13338            return;
13339        }
13340
13341        let Some(row_count) = self.visible_row_count() else {
13342            return;
13343        };
13344
13345        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13346
13347        let effects = if action.center_cursor {
13348            SelectionEffects::scroll(Autoscroll::center())
13349        } else {
13350            SelectionEffects::default()
13351        };
13352
13353        let text_layout_details = &self.text_layout_details(window);
13354        self.change_selections(effects, window, cx, |s| {
13355            s.move_with(|map, selection| {
13356                if !selection.is_empty() {
13357                    selection.goal = SelectionGoal::None;
13358                }
13359                let (cursor, goal) = movement::down_by_rows(
13360                    map,
13361                    selection.end,
13362                    row_count,
13363                    selection.goal,
13364                    false,
13365                    text_layout_details,
13366                );
13367                selection.collapse_to(cursor, goal);
13368            });
13369        });
13370    }
13371
13372    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
13373        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13374        let text_layout_details = &self.text_layout_details(window);
13375        self.change_selections(Default::default(), window, cx, |s| {
13376            s.move_heads_with(|map, head, goal| {
13377                movement::down(map, head, goal, false, text_layout_details)
13378            })
13379        });
13380    }
13381
13382    pub fn context_menu_first(
13383        &mut self,
13384        _: &ContextMenuFirst,
13385        window: &mut Window,
13386        cx: &mut Context<Self>,
13387    ) {
13388        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13389            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
13390        }
13391    }
13392
13393    pub fn context_menu_prev(
13394        &mut self,
13395        _: &ContextMenuPrevious,
13396        window: &mut Window,
13397        cx: &mut Context<Self>,
13398    ) {
13399        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13400            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
13401        }
13402    }
13403
13404    pub fn context_menu_next(
13405        &mut self,
13406        _: &ContextMenuNext,
13407        window: &mut Window,
13408        cx: &mut Context<Self>,
13409    ) {
13410        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13411            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
13412        }
13413    }
13414
13415    pub fn context_menu_last(
13416        &mut self,
13417        _: &ContextMenuLast,
13418        window: &mut Window,
13419        cx: &mut Context<Self>,
13420    ) {
13421        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13422            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
13423        }
13424    }
13425
13426    pub fn signature_help_prev(
13427        &mut self,
13428        _: &SignatureHelpPrevious,
13429        _: &mut Window,
13430        cx: &mut Context<Self>,
13431    ) {
13432        if let Some(popover) = self.signature_help_state.popover_mut() {
13433            if popover.current_signature == 0 {
13434                popover.current_signature = popover.signatures.len() - 1;
13435            } else {
13436                popover.current_signature -= 1;
13437            }
13438            cx.notify();
13439        }
13440    }
13441
13442    pub fn signature_help_next(
13443        &mut self,
13444        _: &SignatureHelpNext,
13445        _: &mut Window,
13446        cx: &mut Context<Self>,
13447    ) {
13448        if let Some(popover) = self.signature_help_state.popover_mut() {
13449            if popover.current_signature + 1 == popover.signatures.len() {
13450                popover.current_signature = 0;
13451            } else {
13452                popover.current_signature += 1;
13453            }
13454            cx.notify();
13455        }
13456    }
13457
13458    pub fn move_to_previous_word_start(
13459        &mut self,
13460        _: &MoveToPreviousWordStart,
13461        window: &mut Window,
13462        cx: &mut Context<Self>,
13463    ) {
13464        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13465        self.change_selections(Default::default(), window, cx, |s| {
13466            s.move_cursors_with(|map, head, _| {
13467                (
13468                    movement::previous_word_start(map, head),
13469                    SelectionGoal::None,
13470                )
13471            });
13472        })
13473    }
13474
13475    pub fn move_to_previous_subword_start(
13476        &mut self,
13477        _: &MoveToPreviousSubwordStart,
13478        window: &mut Window,
13479        cx: &mut Context<Self>,
13480    ) {
13481        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13482        self.change_selections(Default::default(), window, cx, |s| {
13483            s.move_cursors_with(|map, head, _| {
13484                (
13485                    movement::previous_subword_start(map, head),
13486                    SelectionGoal::None,
13487                )
13488            });
13489        })
13490    }
13491
13492    pub fn select_to_previous_word_start(
13493        &mut self,
13494        _: &SelectToPreviousWordStart,
13495        window: &mut Window,
13496        cx: &mut Context<Self>,
13497    ) {
13498        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13499        self.change_selections(Default::default(), window, cx, |s| {
13500            s.move_heads_with(|map, head, _| {
13501                (
13502                    movement::previous_word_start(map, head),
13503                    SelectionGoal::None,
13504                )
13505            });
13506        })
13507    }
13508
13509    pub fn select_to_previous_subword_start(
13510        &mut self,
13511        _: &SelectToPreviousSubwordStart,
13512        window: &mut Window,
13513        cx: &mut Context<Self>,
13514    ) {
13515        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13516        self.change_selections(Default::default(), window, cx, |s| {
13517            s.move_heads_with(|map, head, _| {
13518                (
13519                    movement::previous_subword_start(map, head),
13520                    SelectionGoal::None,
13521                )
13522            });
13523        })
13524    }
13525
13526    pub fn delete_to_previous_word_start(
13527        &mut self,
13528        action: &DeleteToPreviousWordStart,
13529        window: &mut Window,
13530        cx: &mut Context<Self>,
13531    ) {
13532        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13533        self.transact(window, cx, |this, window, cx| {
13534            this.select_autoclose_pair(window, cx);
13535            this.change_selections(Default::default(), window, cx, |s| {
13536                s.move_with(|map, selection| {
13537                    if selection.is_empty() {
13538                        let mut cursor = if action.ignore_newlines {
13539                            movement::previous_word_start(map, selection.head())
13540                        } else {
13541                            movement::previous_word_start_or_newline(map, selection.head())
13542                        };
13543                        cursor = movement::adjust_greedy_deletion(
13544                            map,
13545                            selection.head(),
13546                            cursor,
13547                            action.ignore_brackets,
13548                        );
13549                        selection.set_head(cursor, SelectionGoal::None);
13550                    }
13551                });
13552            });
13553            this.insert("", window, cx);
13554        });
13555    }
13556
13557    pub fn delete_to_previous_subword_start(
13558        &mut self,
13559        _: &DeleteToPreviousSubwordStart,
13560        window: &mut Window,
13561        cx: &mut Context<Self>,
13562    ) {
13563        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13564        self.transact(window, cx, |this, window, cx| {
13565            this.select_autoclose_pair(window, cx);
13566            this.change_selections(Default::default(), window, cx, |s| {
13567                s.move_with(|map, selection| {
13568                    if selection.is_empty() {
13569                        let mut cursor = movement::previous_subword_start(map, selection.head());
13570                        cursor =
13571                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13572                        selection.set_head(cursor, SelectionGoal::None);
13573                    }
13574                });
13575            });
13576            this.insert("", window, cx);
13577        });
13578    }
13579
13580    pub fn move_to_next_word_end(
13581        &mut self,
13582        _: &MoveToNextWordEnd,
13583        window: &mut Window,
13584        cx: &mut Context<Self>,
13585    ) {
13586        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13587        self.change_selections(Default::default(), window, cx, |s| {
13588            s.move_cursors_with(|map, head, _| {
13589                (movement::next_word_end(map, head), SelectionGoal::None)
13590            });
13591        })
13592    }
13593
13594    pub fn move_to_next_subword_end(
13595        &mut self,
13596        _: &MoveToNextSubwordEnd,
13597        window: &mut Window,
13598        cx: &mut Context<Self>,
13599    ) {
13600        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13601        self.change_selections(Default::default(), window, cx, |s| {
13602            s.move_cursors_with(|map, head, _| {
13603                (movement::next_subword_end(map, head), SelectionGoal::None)
13604            });
13605        })
13606    }
13607
13608    pub fn select_to_next_word_end(
13609        &mut self,
13610        _: &SelectToNextWordEnd,
13611        window: &mut Window,
13612        cx: &mut Context<Self>,
13613    ) {
13614        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13615        self.change_selections(Default::default(), window, cx, |s| {
13616            s.move_heads_with(|map, head, _| {
13617                (movement::next_word_end(map, head), SelectionGoal::None)
13618            });
13619        })
13620    }
13621
13622    pub fn select_to_next_subword_end(
13623        &mut self,
13624        _: &SelectToNextSubwordEnd,
13625        window: &mut Window,
13626        cx: &mut Context<Self>,
13627    ) {
13628        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13629        self.change_selections(Default::default(), window, cx, |s| {
13630            s.move_heads_with(|map, head, _| {
13631                (movement::next_subword_end(map, head), SelectionGoal::None)
13632            });
13633        })
13634    }
13635
13636    pub fn delete_to_next_word_end(
13637        &mut self,
13638        action: &DeleteToNextWordEnd,
13639        window: &mut Window,
13640        cx: &mut Context<Self>,
13641    ) {
13642        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13643        self.transact(window, cx, |this, window, cx| {
13644            this.change_selections(Default::default(), window, cx, |s| {
13645                s.move_with(|map, selection| {
13646                    if selection.is_empty() {
13647                        let mut cursor = if action.ignore_newlines {
13648                            movement::next_word_end(map, selection.head())
13649                        } else {
13650                            movement::next_word_end_or_newline(map, selection.head())
13651                        };
13652                        cursor = movement::adjust_greedy_deletion(
13653                            map,
13654                            selection.head(),
13655                            cursor,
13656                            action.ignore_brackets,
13657                        );
13658                        selection.set_head(cursor, SelectionGoal::None);
13659                    }
13660                });
13661            });
13662            this.insert("", window, cx);
13663        });
13664    }
13665
13666    pub fn delete_to_next_subword_end(
13667        &mut self,
13668        _: &DeleteToNextSubwordEnd,
13669        window: &mut Window,
13670        cx: &mut Context<Self>,
13671    ) {
13672        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13673        self.transact(window, cx, |this, window, cx| {
13674            this.change_selections(Default::default(), window, cx, |s| {
13675                s.move_with(|map, selection| {
13676                    if selection.is_empty() {
13677                        let mut cursor = movement::next_subword_end(map, selection.head());
13678                        cursor =
13679                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13680                        selection.set_head(cursor, SelectionGoal::None);
13681                    }
13682                });
13683            });
13684            this.insert("", window, cx);
13685        });
13686    }
13687
13688    pub fn move_to_beginning_of_line(
13689        &mut self,
13690        action: &MoveToBeginningOfLine,
13691        window: &mut Window,
13692        cx: &mut Context<Self>,
13693    ) {
13694        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13695        self.change_selections(Default::default(), window, cx, |s| {
13696            s.move_cursors_with(|map, head, _| {
13697                (
13698                    movement::indented_line_beginning(
13699                        map,
13700                        head,
13701                        action.stop_at_soft_wraps,
13702                        action.stop_at_indent,
13703                    ),
13704                    SelectionGoal::None,
13705                )
13706            });
13707        })
13708    }
13709
13710    pub fn select_to_beginning_of_line(
13711        &mut self,
13712        action: &SelectToBeginningOfLine,
13713        window: &mut Window,
13714        cx: &mut Context<Self>,
13715    ) {
13716        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13717        self.change_selections(Default::default(), window, cx, |s| {
13718            s.move_heads_with(|map, head, _| {
13719                (
13720                    movement::indented_line_beginning(
13721                        map,
13722                        head,
13723                        action.stop_at_soft_wraps,
13724                        action.stop_at_indent,
13725                    ),
13726                    SelectionGoal::None,
13727                )
13728            });
13729        });
13730    }
13731
13732    pub fn delete_to_beginning_of_line(
13733        &mut self,
13734        action: &DeleteToBeginningOfLine,
13735        window: &mut Window,
13736        cx: &mut Context<Self>,
13737    ) {
13738        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13739        self.transact(window, cx, |this, window, cx| {
13740            this.change_selections(Default::default(), window, cx, |s| {
13741                s.move_with(|_, selection| {
13742                    selection.reversed = true;
13743                });
13744            });
13745
13746            this.select_to_beginning_of_line(
13747                &SelectToBeginningOfLine {
13748                    stop_at_soft_wraps: false,
13749                    stop_at_indent: action.stop_at_indent,
13750                },
13751                window,
13752                cx,
13753            );
13754            this.backspace(&Backspace, window, cx);
13755        });
13756    }
13757
13758    pub fn move_to_end_of_line(
13759        &mut self,
13760        action: &MoveToEndOfLine,
13761        window: &mut Window,
13762        cx: &mut Context<Self>,
13763    ) {
13764        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13765        self.change_selections(Default::default(), window, cx, |s| {
13766            s.move_cursors_with(|map, head, _| {
13767                (
13768                    movement::line_end(map, head, action.stop_at_soft_wraps),
13769                    SelectionGoal::None,
13770                )
13771            });
13772        })
13773    }
13774
13775    pub fn select_to_end_of_line(
13776        &mut self,
13777        action: &SelectToEndOfLine,
13778        window: &mut Window,
13779        cx: &mut Context<Self>,
13780    ) {
13781        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13782        self.change_selections(Default::default(), window, cx, |s| {
13783            s.move_heads_with(|map, head, _| {
13784                (
13785                    movement::line_end(map, head, action.stop_at_soft_wraps),
13786                    SelectionGoal::None,
13787                )
13788            });
13789        })
13790    }
13791
13792    pub fn delete_to_end_of_line(
13793        &mut self,
13794        _: &DeleteToEndOfLine,
13795        window: &mut Window,
13796        cx: &mut Context<Self>,
13797    ) {
13798        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13799        self.transact(window, cx, |this, window, cx| {
13800            this.select_to_end_of_line(
13801                &SelectToEndOfLine {
13802                    stop_at_soft_wraps: false,
13803                },
13804                window,
13805                cx,
13806            );
13807            this.delete(&Delete, window, cx);
13808        });
13809    }
13810
13811    pub fn cut_to_end_of_line(
13812        &mut self,
13813        action: &CutToEndOfLine,
13814        window: &mut Window,
13815        cx: &mut Context<Self>,
13816    ) {
13817        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13818        self.transact(window, cx, |this, window, cx| {
13819            this.select_to_end_of_line(
13820                &SelectToEndOfLine {
13821                    stop_at_soft_wraps: false,
13822                },
13823                window,
13824                cx,
13825            );
13826            if !action.stop_at_newlines {
13827                this.change_selections(Default::default(), window, cx, |s| {
13828                    s.move_with(|_, sel| {
13829                        if sel.is_empty() {
13830                            sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
13831                        }
13832                    });
13833                });
13834            }
13835            this.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13836            let item = this.cut_common(false, window, cx);
13837            cx.write_to_clipboard(item);
13838        });
13839    }
13840
13841    pub fn move_to_start_of_paragraph(
13842        &mut self,
13843        _: &MoveToStartOfParagraph,
13844        window: &mut Window,
13845        cx: &mut Context<Self>,
13846    ) {
13847        if matches!(self.mode, EditorMode::SingleLine) {
13848            cx.propagate();
13849            return;
13850        }
13851        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13852        self.change_selections(Default::default(), window, cx, |s| {
13853            s.move_with(|map, selection| {
13854                selection.collapse_to(
13855                    movement::start_of_paragraph(map, selection.head(), 1),
13856                    SelectionGoal::None,
13857                )
13858            });
13859        })
13860    }
13861
13862    pub fn move_to_end_of_paragraph(
13863        &mut self,
13864        _: &MoveToEndOfParagraph,
13865        window: &mut Window,
13866        cx: &mut Context<Self>,
13867    ) {
13868        if matches!(self.mode, EditorMode::SingleLine) {
13869            cx.propagate();
13870            return;
13871        }
13872        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13873        self.change_selections(Default::default(), window, cx, |s| {
13874            s.move_with(|map, selection| {
13875                selection.collapse_to(
13876                    movement::end_of_paragraph(map, selection.head(), 1),
13877                    SelectionGoal::None,
13878                )
13879            });
13880        })
13881    }
13882
13883    pub fn select_to_start_of_paragraph(
13884        &mut self,
13885        _: &SelectToStartOfParagraph,
13886        window: &mut Window,
13887        cx: &mut Context<Self>,
13888    ) {
13889        if matches!(self.mode, EditorMode::SingleLine) {
13890            cx.propagate();
13891            return;
13892        }
13893        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13894        self.change_selections(Default::default(), window, cx, |s| {
13895            s.move_heads_with(|map, head, _| {
13896                (
13897                    movement::start_of_paragraph(map, head, 1),
13898                    SelectionGoal::None,
13899                )
13900            });
13901        })
13902    }
13903
13904    pub fn select_to_end_of_paragraph(
13905        &mut self,
13906        _: &SelectToEndOfParagraph,
13907        window: &mut Window,
13908        cx: &mut Context<Self>,
13909    ) {
13910        if matches!(self.mode, EditorMode::SingleLine) {
13911            cx.propagate();
13912            return;
13913        }
13914        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13915        self.change_selections(Default::default(), window, cx, |s| {
13916            s.move_heads_with(|map, head, _| {
13917                (
13918                    movement::end_of_paragraph(map, head, 1),
13919                    SelectionGoal::None,
13920                )
13921            });
13922        })
13923    }
13924
13925    pub fn move_to_start_of_excerpt(
13926        &mut self,
13927        _: &MoveToStartOfExcerpt,
13928        window: &mut Window,
13929        cx: &mut Context<Self>,
13930    ) {
13931        if matches!(self.mode, EditorMode::SingleLine) {
13932            cx.propagate();
13933            return;
13934        }
13935        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13936        self.change_selections(Default::default(), window, cx, |s| {
13937            s.move_with(|map, selection| {
13938                selection.collapse_to(
13939                    movement::start_of_excerpt(
13940                        map,
13941                        selection.head(),
13942                        workspace::searchable::Direction::Prev,
13943                    ),
13944                    SelectionGoal::None,
13945                )
13946            });
13947        })
13948    }
13949
13950    pub fn move_to_start_of_next_excerpt(
13951        &mut self,
13952        _: &MoveToStartOfNextExcerpt,
13953        window: &mut Window,
13954        cx: &mut Context<Self>,
13955    ) {
13956        if matches!(self.mode, EditorMode::SingleLine) {
13957            cx.propagate();
13958            return;
13959        }
13960
13961        self.change_selections(Default::default(), window, cx, |s| {
13962            s.move_with(|map, selection| {
13963                selection.collapse_to(
13964                    movement::start_of_excerpt(
13965                        map,
13966                        selection.head(),
13967                        workspace::searchable::Direction::Next,
13968                    ),
13969                    SelectionGoal::None,
13970                )
13971            });
13972        })
13973    }
13974
13975    pub fn move_to_end_of_excerpt(
13976        &mut self,
13977        _: &MoveToEndOfExcerpt,
13978        window: &mut Window,
13979        cx: &mut Context<Self>,
13980    ) {
13981        if matches!(self.mode, EditorMode::SingleLine) {
13982            cx.propagate();
13983            return;
13984        }
13985        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13986        self.change_selections(Default::default(), window, cx, |s| {
13987            s.move_with(|map, selection| {
13988                selection.collapse_to(
13989                    movement::end_of_excerpt(
13990                        map,
13991                        selection.head(),
13992                        workspace::searchable::Direction::Next,
13993                    ),
13994                    SelectionGoal::None,
13995                )
13996            });
13997        })
13998    }
13999
14000    pub fn move_to_end_of_previous_excerpt(
14001        &mut self,
14002        _: &MoveToEndOfPreviousExcerpt,
14003        window: &mut Window,
14004        cx: &mut Context<Self>,
14005    ) {
14006        if matches!(self.mode, EditorMode::SingleLine) {
14007            cx.propagate();
14008            return;
14009        }
14010        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14011        self.change_selections(Default::default(), window, cx, |s| {
14012            s.move_with(|map, selection| {
14013                selection.collapse_to(
14014                    movement::end_of_excerpt(
14015                        map,
14016                        selection.head(),
14017                        workspace::searchable::Direction::Prev,
14018                    ),
14019                    SelectionGoal::None,
14020                )
14021            });
14022        })
14023    }
14024
14025    pub fn select_to_start_of_excerpt(
14026        &mut self,
14027        _: &SelectToStartOfExcerpt,
14028        window: &mut Window,
14029        cx: &mut Context<Self>,
14030    ) {
14031        if matches!(self.mode, EditorMode::SingleLine) {
14032            cx.propagate();
14033            return;
14034        }
14035        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14036        self.change_selections(Default::default(), window, cx, |s| {
14037            s.move_heads_with(|map, head, _| {
14038                (
14039                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
14040                    SelectionGoal::None,
14041                )
14042            });
14043        })
14044    }
14045
14046    pub fn select_to_start_of_next_excerpt(
14047        &mut self,
14048        _: &SelectToStartOfNextExcerpt,
14049        window: &mut Window,
14050        cx: &mut Context<Self>,
14051    ) {
14052        if matches!(self.mode, EditorMode::SingleLine) {
14053            cx.propagate();
14054            return;
14055        }
14056        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14057        self.change_selections(Default::default(), window, cx, |s| {
14058            s.move_heads_with(|map, head, _| {
14059                (
14060                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
14061                    SelectionGoal::None,
14062                )
14063            });
14064        })
14065    }
14066
14067    pub fn select_to_end_of_excerpt(
14068        &mut self,
14069        _: &SelectToEndOfExcerpt,
14070        window: &mut Window,
14071        cx: &mut Context<Self>,
14072    ) {
14073        if matches!(self.mode, EditorMode::SingleLine) {
14074            cx.propagate();
14075            return;
14076        }
14077        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14078        self.change_selections(Default::default(), window, cx, |s| {
14079            s.move_heads_with(|map, head, _| {
14080                (
14081                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
14082                    SelectionGoal::None,
14083                )
14084            });
14085        })
14086    }
14087
14088    pub fn select_to_end_of_previous_excerpt(
14089        &mut self,
14090        _: &SelectToEndOfPreviousExcerpt,
14091        window: &mut Window,
14092        cx: &mut Context<Self>,
14093    ) {
14094        if matches!(self.mode, EditorMode::SingleLine) {
14095            cx.propagate();
14096            return;
14097        }
14098        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14099        self.change_selections(Default::default(), window, cx, |s| {
14100            s.move_heads_with(|map, head, _| {
14101                (
14102                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
14103                    SelectionGoal::None,
14104                )
14105            });
14106        })
14107    }
14108
14109    pub fn move_to_beginning(
14110        &mut self,
14111        _: &MoveToBeginning,
14112        window: &mut Window,
14113        cx: &mut Context<Self>,
14114    ) {
14115        if matches!(self.mode, EditorMode::SingleLine) {
14116            cx.propagate();
14117            return;
14118        }
14119        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14120        self.change_selections(Default::default(), window, cx, |s| {
14121            s.select_ranges(vec![0..0]);
14122        });
14123    }
14124
14125    pub fn select_to_beginning(
14126        &mut self,
14127        _: &SelectToBeginning,
14128        window: &mut Window,
14129        cx: &mut Context<Self>,
14130    ) {
14131        let mut selection = self.selections.last::<Point>(&self.display_snapshot(cx));
14132        selection.set_head(Point::zero(), SelectionGoal::None);
14133        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14134        self.change_selections(Default::default(), window, cx, |s| {
14135            s.select(vec![selection]);
14136        });
14137    }
14138
14139    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
14140        if matches!(self.mode, EditorMode::SingleLine) {
14141            cx.propagate();
14142            return;
14143        }
14144        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14145        let cursor = self.buffer.read(cx).read(cx).len();
14146        self.change_selections(Default::default(), window, cx, |s| {
14147            s.select_ranges(vec![cursor..cursor])
14148        });
14149    }
14150
14151    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
14152        self.nav_history = nav_history;
14153    }
14154
14155    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
14156        self.nav_history.as_ref()
14157    }
14158
14159    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
14160        self.push_to_nav_history(
14161            self.selections.newest_anchor().head(),
14162            None,
14163            false,
14164            true,
14165            cx,
14166        );
14167    }
14168
14169    fn push_to_nav_history(
14170        &mut self,
14171        cursor_anchor: Anchor,
14172        new_position: Option<Point>,
14173        is_deactivate: bool,
14174        always: bool,
14175        cx: &mut Context<Self>,
14176    ) {
14177        if let Some(nav_history) = self.nav_history.as_mut() {
14178            let buffer = self.buffer.read(cx).read(cx);
14179            let cursor_position = cursor_anchor.to_point(&buffer);
14180            let scroll_state = self.scroll_manager.anchor();
14181            let scroll_top_row = scroll_state.top_row(&buffer);
14182            drop(buffer);
14183
14184            if let Some(new_position) = new_position {
14185                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
14186                if row_delta == 0 || (row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA && !always) {
14187                    return;
14188                }
14189            }
14190
14191            nav_history.push(
14192                Some(NavigationData {
14193                    cursor_anchor,
14194                    cursor_position,
14195                    scroll_anchor: scroll_state,
14196                    scroll_top_row,
14197                }),
14198                cx,
14199            );
14200            cx.emit(EditorEvent::PushedToNavHistory {
14201                anchor: cursor_anchor,
14202                is_deactivate,
14203            })
14204        }
14205    }
14206
14207    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
14208        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14209        let buffer = self.buffer.read(cx).snapshot(cx);
14210        let mut selection = self.selections.first::<usize>(&self.display_snapshot(cx));
14211        selection.set_head(buffer.len(), SelectionGoal::None);
14212        self.change_selections(Default::default(), window, cx, |s| {
14213            s.select(vec![selection]);
14214        });
14215    }
14216
14217    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
14218        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14219        let end = self.buffer.read(cx).read(cx).len();
14220        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14221            s.select_ranges(vec![0..end]);
14222        });
14223    }
14224
14225    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
14226        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14227        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14228        let mut selections = self.selections.all::<Point>(&display_map);
14229        let max_point = display_map.buffer_snapshot().max_point();
14230        for selection in &mut selections {
14231            let rows = selection.spanned_rows(true, &display_map);
14232            selection.start = Point::new(rows.start.0, 0);
14233            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
14234            selection.reversed = false;
14235        }
14236        self.change_selections(Default::default(), window, cx, |s| {
14237            s.select(selections);
14238        });
14239    }
14240
14241    pub fn split_selection_into_lines(
14242        &mut self,
14243        action: &SplitSelectionIntoLines,
14244        window: &mut Window,
14245        cx: &mut Context<Self>,
14246    ) {
14247        let selections = self
14248            .selections
14249            .all::<Point>(&self.display_snapshot(cx))
14250            .into_iter()
14251            .map(|selection| selection.start..selection.end)
14252            .collect::<Vec<_>>();
14253        self.unfold_ranges(&selections, true, true, cx);
14254
14255        let mut new_selection_ranges = Vec::new();
14256        {
14257            let buffer = self.buffer.read(cx).read(cx);
14258            for selection in selections {
14259                for row in selection.start.row..selection.end.row {
14260                    let line_start = Point::new(row, 0);
14261                    let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
14262
14263                    if action.keep_selections {
14264                        // Keep the selection range for each line
14265                        let selection_start = if row == selection.start.row {
14266                            selection.start
14267                        } else {
14268                            line_start
14269                        };
14270                        new_selection_ranges.push(selection_start..line_end);
14271                    } else {
14272                        // Collapse to cursor at end of line
14273                        new_selection_ranges.push(line_end..line_end);
14274                    }
14275                }
14276
14277                let is_multiline_selection = selection.start.row != selection.end.row;
14278                // Don't insert last one if it's a multi-line selection ending at the start of a line,
14279                // so this action feels more ergonomic when paired with other selection operations
14280                let should_skip_last = is_multiline_selection && selection.end.column == 0;
14281                if !should_skip_last {
14282                    if action.keep_selections {
14283                        if is_multiline_selection {
14284                            let line_start = Point::new(selection.end.row, 0);
14285                            new_selection_ranges.push(line_start..selection.end);
14286                        } else {
14287                            new_selection_ranges.push(selection.start..selection.end);
14288                        }
14289                    } else {
14290                        new_selection_ranges.push(selection.end..selection.end);
14291                    }
14292                }
14293            }
14294        }
14295        self.change_selections(Default::default(), window, cx, |s| {
14296            s.select_ranges(new_selection_ranges);
14297        });
14298    }
14299
14300    pub fn add_selection_above(
14301        &mut self,
14302        action: &AddSelectionAbove,
14303        window: &mut Window,
14304        cx: &mut Context<Self>,
14305    ) {
14306        self.add_selection(true, action.skip_soft_wrap, window, cx);
14307    }
14308
14309    pub fn add_selection_below(
14310        &mut self,
14311        action: &AddSelectionBelow,
14312        window: &mut Window,
14313        cx: &mut Context<Self>,
14314    ) {
14315        self.add_selection(false, action.skip_soft_wrap, window, cx);
14316    }
14317
14318    fn add_selection(
14319        &mut self,
14320        above: bool,
14321        skip_soft_wrap: bool,
14322        window: &mut Window,
14323        cx: &mut Context<Self>,
14324    ) {
14325        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14326
14327        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14328        let all_selections = self.selections.all::<Point>(&display_map);
14329        let text_layout_details = self.text_layout_details(window);
14330
14331        let (mut columnar_selections, new_selections_to_columnarize) = {
14332            if let Some(state) = self.add_selections_state.as_ref() {
14333                let columnar_selection_ids: HashSet<_> = state
14334                    .groups
14335                    .iter()
14336                    .flat_map(|group| group.stack.iter())
14337                    .copied()
14338                    .collect();
14339
14340                all_selections
14341                    .into_iter()
14342                    .partition(|s| columnar_selection_ids.contains(&s.id))
14343            } else {
14344                (Vec::new(), all_selections)
14345            }
14346        };
14347
14348        let mut state = self
14349            .add_selections_state
14350            .take()
14351            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
14352
14353        for selection in new_selections_to_columnarize {
14354            let range = selection.display_range(&display_map).sorted();
14355            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
14356            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
14357            let positions = start_x.min(end_x)..start_x.max(end_x);
14358            let mut stack = Vec::new();
14359            for row in range.start.row().0..=range.end.row().0 {
14360                if let Some(selection) = self.selections.build_columnar_selection(
14361                    &display_map,
14362                    DisplayRow(row),
14363                    &positions,
14364                    selection.reversed,
14365                    &text_layout_details,
14366                ) {
14367                    stack.push(selection.id);
14368                    columnar_selections.push(selection);
14369                }
14370            }
14371            if !stack.is_empty() {
14372                if above {
14373                    stack.reverse();
14374                }
14375                state.groups.push(AddSelectionsGroup { above, stack });
14376            }
14377        }
14378
14379        let mut final_selections = Vec::new();
14380        let end_row = if above {
14381            DisplayRow(0)
14382        } else {
14383            display_map.max_point().row()
14384        };
14385
14386        let mut last_added_item_per_group = HashMap::default();
14387        for group in state.groups.iter_mut() {
14388            if let Some(last_id) = group.stack.last() {
14389                last_added_item_per_group.insert(*last_id, group);
14390            }
14391        }
14392
14393        for selection in columnar_selections {
14394            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
14395                if above == group.above {
14396                    let range = selection.display_range(&display_map).sorted();
14397                    debug_assert_eq!(range.start.row(), range.end.row());
14398                    let mut row = range.start.row();
14399                    let positions =
14400                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
14401                            Pixels::from(start)..Pixels::from(end)
14402                        } else {
14403                            let start_x =
14404                                display_map.x_for_display_point(range.start, &text_layout_details);
14405                            let end_x =
14406                                display_map.x_for_display_point(range.end, &text_layout_details);
14407                            start_x.min(end_x)..start_x.max(end_x)
14408                        };
14409
14410                    let mut maybe_new_selection = None;
14411                    let direction = if above { -1 } else { 1 };
14412
14413                    while row != end_row {
14414                        if skip_soft_wrap {
14415                            row = display_map
14416                                .start_of_relative_buffer_row(DisplayPoint::new(row, 0), direction)
14417                                .row();
14418                        } else if above {
14419                            row.0 -= 1;
14420                        } else {
14421                            row.0 += 1;
14422                        }
14423
14424                        if let Some(new_selection) = self.selections.build_columnar_selection(
14425                            &display_map,
14426                            row,
14427                            &positions,
14428                            selection.reversed,
14429                            &text_layout_details,
14430                        ) {
14431                            maybe_new_selection = Some(new_selection);
14432                            break;
14433                        }
14434                    }
14435
14436                    if let Some(new_selection) = maybe_new_selection {
14437                        group.stack.push(new_selection.id);
14438                        if above {
14439                            final_selections.push(new_selection);
14440                            final_selections.push(selection);
14441                        } else {
14442                            final_selections.push(selection);
14443                            final_selections.push(new_selection);
14444                        }
14445                    } else {
14446                        final_selections.push(selection);
14447                    }
14448                } else {
14449                    group.stack.pop();
14450                }
14451            } else {
14452                final_selections.push(selection);
14453            }
14454        }
14455
14456        self.change_selections(Default::default(), window, cx, |s| {
14457            s.select(final_selections);
14458        });
14459
14460        let final_selection_ids: HashSet<_> = self
14461            .selections
14462            .all::<Point>(&display_map)
14463            .iter()
14464            .map(|s| s.id)
14465            .collect();
14466        state.groups.retain_mut(|group| {
14467            // selections might get merged above so we remove invalid items from stacks
14468            group.stack.retain(|id| final_selection_ids.contains(id));
14469
14470            // single selection in stack can be treated as initial state
14471            group.stack.len() > 1
14472        });
14473
14474        if !state.groups.is_empty() {
14475            self.add_selections_state = Some(state);
14476        }
14477    }
14478
14479    fn select_match_ranges(
14480        &mut self,
14481        range: Range<usize>,
14482        reversed: bool,
14483        replace_newest: bool,
14484        auto_scroll: Option<Autoscroll>,
14485        window: &mut Window,
14486        cx: &mut Context<Editor>,
14487    ) {
14488        self.unfold_ranges(
14489            std::slice::from_ref(&range),
14490            false,
14491            auto_scroll.is_some(),
14492            cx,
14493        );
14494        let effects = if let Some(scroll) = auto_scroll {
14495            SelectionEffects::scroll(scroll)
14496        } else {
14497            SelectionEffects::no_scroll()
14498        };
14499        self.change_selections(effects, window, cx, |s| {
14500            if replace_newest {
14501                s.delete(s.newest_anchor().id);
14502            }
14503            if reversed {
14504                s.insert_range(range.end..range.start);
14505            } else {
14506                s.insert_range(range);
14507            }
14508        });
14509    }
14510
14511    pub fn select_next_match_internal(
14512        &mut self,
14513        display_map: &DisplaySnapshot,
14514        replace_newest: bool,
14515        autoscroll: Option<Autoscroll>,
14516        window: &mut Window,
14517        cx: &mut Context<Self>,
14518    ) -> Result<()> {
14519        let buffer = display_map.buffer_snapshot();
14520        let mut selections = self.selections.all::<usize>(&display_map);
14521        if let Some(mut select_next_state) = self.select_next_state.take() {
14522            let query = &select_next_state.query;
14523            if !select_next_state.done {
14524                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14525                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14526                let mut next_selected_range = None;
14527
14528                let bytes_after_last_selection =
14529                    buffer.bytes_in_range(last_selection.end..buffer.len());
14530                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
14531                let query_matches = query
14532                    .stream_find_iter(bytes_after_last_selection)
14533                    .map(|result| (last_selection.end, result))
14534                    .chain(
14535                        query
14536                            .stream_find_iter(bytes_before_first_selection)
14537                            .map(|result| (0, result)),
14538                    );
14539
14540                for (start_offset, query_match) in query_matches {
14541                    let query_match = query_match.unwrap(); // can only fail due to I/O
14542                    let offset_range =
14543                        start_offset + query_match.start()..start_offset + query_match.end();
14544
14545                    if !select_next_state.wordwise
14546                        || (!buffer.is_inside_word(offset_range.start, None)
14547                            && !buffer.is_inside_word(offset_range.end, None))
14548                    {
14549                        let idx = selections
14550                            .partition_point(|selection| selection.end <= offset_range.start);
14551                        let overlaps = selections
14552                            .get(idx)
14553                            .map_or(false, |selection| selection.start < offset_range.end);
14554
14555                        if !overlaps {
14556                            next_selected_range = Some(offset_range);
14557                            break;
14558                        }
14559                    }
14560                }
14561
14562                if let Some(next_selected_range) = next_selected_range {
14563                    self.select_match_ranges(
14564                        next_selected_range,
14565                        last_selection.reversed,
14566                        replace_newest,
14567                        autoscroll,
14568                        window,
14569                        cx,
14570                    );
14571                } else {
14572                    select_next_state.done = true;
14573                }
14574            }
14575
14576            self.select_next_state = Some(select_next_state);
14577        } else {
14578            let mut only_carets = true;
14579            let mut same_text_selected = true;
14580            let mut selected_text = None;
14581
14582            let mut selections_iter = selections.iter().peekable();
14583            while let Some(selection) = selections_iter.next() {
14584                if selection.start != selection.end {
14585                    only_carets = false;
14586                }
14587
14588                if same_text_selected {
14589                    if selected_text.is_none() {
14590                        selected_text =
14591                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14592                    }
14593
14594                    if let Some(next_selection) = selections_iter.peek() {
14595                        if next_selection.range().len() == selection.range().len() {
14596                            let next_selected_text = buffer
14597                                .text_for_range(next_selection.range())
14598                                .collect::<String>();
14599                            if Some(next_selected_text) != selected_text {
14600                                same_text_selected = false;
14601                                selected_text = None;
14602                            }
14603                        } else {
14604                            same_text_selected = false;
14605                            selected_text = None;
14606                        }
14607                    }
14608                }
14609            }
14610
14611            if only_carets {
14612                for selection in &mut selections {
14613                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
14614                    selection.start = word_range.start;
14615                    selection.end = word_range.end;
14616                    selection.goal = SelectionGoal::None;
14617                    selection.reversed = false;
14618                    self.select_match_ranges(
14619                        selection.start..selection.end,
14620                        selection.reversed,
14621                        replace_newest,
14622                        autoscroll,
14623                        window,
14624                        cx,
14625                    );
14626                }
14627
14628                if selections.len() == 1 {
14629                    let selection = selections
14630                        .last()
14631                        .expect("ensured that there's only one selection");
14632                    let query = buffer
14633                        .text_for_range(selection.start..selection.end)
14634                        .collect::<String>();
14635                    let is_empty = query.is_empty();
14636                    let select_state = SelectNextState {
14637                        query: AhoCorasick::new(&[query])?,
14638                        wordwise: true,
14639                        done: is_empty,
14640                    };
14641                    self.select_next_state = Some(select_state);
14642                } else {
14643                    self.select_next_state = None;
14644                }
14645            } else if let Some(selected_text) = selected_text {
14646                self.select_next_state = Some(SelectNextState {
14647                    query: AhoCorasick::new(&[selected_text])?,
14648                    wordwise: false,
14649                    done: false,
14650                });
14651                self.select_next_match_internal(
14652                    display_map,
14653                    replace_newest,
14654                    autoscroll,
14655                    window,
14656                    cx,
14657                )?;
14658            }
14659        }
14660        Ok(())
14661    }
14662
14663    pub fn select_all_matches(
14664        &mut self,
14665        _action: &SelectAllMatches,
14666        window: &mut Window,
14667        cx: &mut Context<Self>,
14668    ) -> Result<()> {
14669        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14670
14671        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14672
14673        self.select_next_match_internal(&display_map, false, None, window, cx)?;
14674        let Some(select_next_state) = self.select_next_state.as_mut() else {
14675            return Ok(());
14676        };
14677        if select_next_state.done {
14678            return Ok(());
14679        }
14680
14681        let mut new_selections = Vec::new();
14682
14683        let reversed = self.selections.oldest::<usize>(&display_map).reversed;
14684        let buffer = display_map.buffer_snapshot();
14685        let query_matches = select_next_state
14686            .query
14687            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
14688
14689        for query_match in query_matches.into_iter() {
14690            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
14691            let offset_range = if reversed {
14692                query_match.end()..query_match.start()
14693            } else {
14694                query_match.start()..query_match.end()
14695            };
14696
14697            if !select_next_state.wordwise
14698                || (!buffer.is_inside_word(offset_range.start, None)
14699                    && !buffer.is_inside_word(offset_range.end, None))
14700            {
14701                new_selections.push(offset_range.start..offset_range.end);
14702            }
14703        }
14704
14705        select_next_state.done = true;
14706
14707        if new_selections.is_empty() {
14708            log::error!("bug: new_selections is empty in select_all_matches");
14709            return Ok(());
14710        }
14711
14712        self.unfold_ranges(&new_selections.clone(), false, false, cx);
14713        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
14714            selections.select_ranges(new_selections)
14715        });
14716
14717        Ok(())
14718    }
14719
14720    pub fn select_next(
14721        &mut self,
14722        action: &SelectNext,
14723        window: &mut Window,
14724        cx: &mut Context<Self>,
14725    ) -> Result<()> {
14726        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14727        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14728        self.select_next_match_internal(
14729            &display_map,
14730            action.replace_newest,
14731            Some(Autoscroll::newest()),
14732            window,
14733            cx,
14734        )?;
14735        Ok(())
14736    }
14737
14738    pub fn select_previous(
14739        &mut self,
14740        action: &SelectPrevious,
14741        window: &mut Window,
14742        cx: &mut Context<Self>,
14743    ) -> Result<()> {
14744        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14745        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14746        let buffer = display_map.buffer_snapshot();
14747        let mut selections = self.selections.all::<usize>(&display_map);
14748        if let Some(mut select_prev_state) = self.select_prev_state.take() {
14749            let query = &select_prev_state.query;
14750            if !select_prev_state.done {
14751                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14752                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14753                let mut next_selected_range = None;
14754                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
14755                let bytes_before_last_selection =
14756                    buffer.reversed_bytes_in_range(0..last_selection.start);
14757                let bytes_after_first_selection =
14758                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
14759                let query_matches = query
14760                    .stream_find_iter(bytes_before_last_selection)
14761                    .map(|result| (last_selection.start, result))
14762                    .chain(
14763                        query
14764                            .stream_find_iter(bytes_after_first_selection)
14765                            .map(|result| (buffer.len(), result)),
14766                    );
14767                for (end_offset, query_match) in query_matches {
14768                    let query_match = query_match.unwrap(); // can only fail due to I/O
14769                    let offset_range =
14770                        end_offset - query_match.end()..end_offset - query_match.start();
14771
14772                    if !select_prev_state.wordwise
14773                        || (!buffer.is_inside_word(offset_range.start, None)
14774                            && !buffer.is_inside_word(offset_range.end, None))
14775                    {
14776                        next_selected_range = Some(offset_range);
14777                        break;
14778                    }
14779                }
14780
14781                if let Some(next_selected_range) = next_selected_range {
14782                    self.select_match_ranges(
14783                        next_selected_range,
14784                        last_selection.reversed,
14785                        action.replace_newest,
14786                        Some(Autoscroll::newest()),
14787                        window,
14788                        cx,
14789                    );
14790                } else {
14791                    select_prev_state.done = true;
14792                }
14793            }
14794
14795            self.select_prev_state = Some(select_prev_state);
14796        } else {
14797            let mut only_carets = true;
14798            let mut same_text_selected = true;
14799            let mut selected_text = None;
14800
14801            let mut selections_iter = selections.iter().peekable();
14802            while let Some(selection) = selections_iter.next() {
14803                if selection.start != selection.end {
14804                    only_carets = false;
14805                }
14806
14807                if same_text_selected {
14808                    if selected_text.is_none() {
14809                        selected_text =
14810                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14811                    }
14812
14813                    if let Some(next_selection) = selections_iter.peek() {
14814                        if next_selection.range().len() == selection.range().len() {
14815                            let next_selected_text = buffer
14816                                .text_for_range(next_selection.range())
14817                                .collect::<String>();
14818                            if Some(next_selected_text) != selected_text {
14819                                same_text_selected = false;
14820                                selected_text = None;
14821                            }
14822                        } else {
14823                            same_text_selected = false;
14824                            selected_text = None;
14825                        }
14826                    }
14827                }
14828            }
14829
14830            if only_carets {
14831                for selection in &mut selections {
14832                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
14833                    selection.start = word_range.start;
14834                    selection.end = word_range.end;
14835                    selection.goal = SelectionGoal::None;
14836                    selection.reversed = false;
14837                    self.select_match_ranges(
14838                        selection.start..selection.end,
14839                        selection.reversed,
14840                        action.replace_newest,
14841                        Some(Autoscroll::newest()),
14842                        window,
14843                        cx,
14844                    );
14845                }
14846                if selections.len() == 1 {
14847                    let selection = selections
14848                        .last()
14849                        .expect("ensured that there's only one selection");
14850                    let query = buffer
14851                        .text_for_range(selection.start..selection.end)
14852                        .collect::<String>();
14853                    let is_empty = query.is_empty();
14854                    let select_state = SelectNextState {
14855                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
14856                        wordwise: true,
14857                        done: is_empty,
14858                    };
14859                    self.select_prev_state = Some(select_state);
14860                } else {
14861                    self.select_prev_state = None;
14862                }
14863            } else if let Some(selected_text) = selected_text {
14864                self.select_prev_state = Some(SelectNextState {
14865                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
14866                    wordwise: false,
14867                    done: false,
14868                });
14869                self.select_previous(action, window, cx)?;
14870            }
14871        }
14872        Ok(())
14873    }
14874
14875    pub fn find_next_match(
14876        &mut self,
14877        _: &FindNextMatch,
14878        window: &mut Window,
14879        cx: &mut Context<Self>,
14880    ) -> Result<()> {
14881        let selections = self.selections.disjoint_anchors_arc();
14882        match selections.first() {
14883            Some(first) if selections.len() >= 2 => {
14884                self.change_selections(Default::default(), window, cx, |s| {
14885                    s.select_ranges([first.range()]);
14886                });
14887            }
14888            _ => self.select_next(
14889                &SelectNext {
14890                    replace_newest: true,
14891                },
14892                window,
14893                cx,
14894            )?,
14895        }
14896        Ok(())
14897    }
14898
14899    pub fn find_previous_match(
14900        &mut self,
14901        _: &FindPreviousMatch,
14902        window: &mut Window,
14903        cx: &mut Context<Self>,
14904    ) -> Result<()> {
14905        let selections = self.selections.disjoint_anchors_arc();
14906        match selections.last() {
14907            Some(last) if selections.len() >= 2 => {
14908                self.change_selections(Default::default(), window, cx, |s| {
14909                    s.select_ranges([last.range()]);
14910                });
14911            }
14912            _ => self.select_previous(
14913                &SelectPrevious {
14914                    replace_newest: true,
14915                },
14916                window,
14917                cx,
14918            )?,
14919        }
14920        Ok(())
14921    }
14922
14923    pub fn toggle_comments(
14924        &mut self,
14925        action: &ToggleComments,
14926        window: &mut Window,
14927        cx: &mut Context<Self>,
14928    ) {
14929        if self.read_only(cx) {
14930            return;
14931        }
14932        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14933        let text_layout_details = &self.text_layout_details(window);
14934        self.transact(window, cx, |this, window, cx| {
14935            let mut selections = this
14936                .selections
14937                .all::<MultiBufferPoint>(&this.display_snapshot(cx));
14938            let mut edits = Vec::new();
14939            let mut selection_edit_ranges = Vec::new();
14940            let mut last_toggled_row = None;
14941            let snapshot = this.buffer.read(cx).read(cx);
14942            let empty_str: Arc<str> = Arc::default();
14943            let mut suffixes_inserted = Vec::new();
14944            let ignore_indent = action.ignore_indent;
14945
14946            fn comment_prefix_range(
14947                snapshot: &MultiBufferSnapshot,
14948                row: MultiBufferRow,
14949                comment_prefix: &str,
14950                comment_prefix_whitespace: &str,
14951                ignore_indent: bool,
14952            ) -> Range<Point> {
14953                let indent_size = if ignore_indent {
14954                    0
14955                } else {
14956                    snapshot.indent_size_for_line(row).len
14957                };
14958
14959                let start = Point::new(row.0, indent_size);
14960
14961                let mut line_bytes = snapshot
14962                    .bytes_in_range(start..snapshot.max_point())
14963                    .flatten()
14964                    .copied();
14965
14966                // If this line currently begins with the line comment prefix, then record
14967                // the range containing the prefix.
14968                if line_bytes
14969                    .by_ref()
14970                    .take(comment_prefix.len())
14971                    .eq(comment_prefix.bytes())
14972                {
14973                    // Include any whitespace that matches the comment prefix.
14974                    let matching_whitespace_len = line_bytes
14975                        .zip(comment_prefix_whitespace.bytes())
14976                        .take_while(|(a, b)| a == b)
14977                        .count() as u32;
14978                    let end = Point::new(
14979                        start.row,
14980                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
14981                    );
14982                    start..end
14983                } else {
14984                    start..start
14985                }
14986            }
14987
14988            fn comment_suffix_range(
14989                snapshot: &MultiBufferSnapshot,
14990                row: MultiBufferRow,
14991                comment_suffix: &str,
14992                comment_suffix_has_leading_space: bool,
14993            ) -> Range<Point> {
14994                let end = Point::new(row.0, snapshot.line_len(row));
14995                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
14996
14997                let mut line_end_bytes = snapshot
14998                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
14999                    .flatten()
15000                    .copied();
15001
15002                let leading_space_len = if suffix_start_column > 0
15003                    && line_end_bytes.next() == Some(b' ')
15004                    && comment_suffix_has_leading_space
15005                {
15006                    1
15007                } else {
15008                    0
15009                };
15010
15011                // If this line currently begins with the line comment prefix, then record
15012                // the range containing the prefix.
15013                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
15014                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
15015                    start..end
15016                } else {
15017                    end..end
15018                }
15019            }
15020
15021            // TODO: Handle selections that cross excerpts
15022            for selection in &mut selections {
15023                let start_column = snapshot
15024                    .indent_size_for_line(MultiBufferRow(selection.start.row))
15025                    .len;
15026                let language = if let Some(language) =
15027                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
15028                {
15029                    language
15030                } else {
15031                    continue;
15032                };
15033
15034                selection_edit_ranges.clear();
15035
15036                // If multiple selections contain a given row, avoid processing that
15037                // row more than once.
15038                let mut start_row = MultiBufferRow(selection.start.row);
15039                if last_toggled_row == Some(start_row) {
15040                    start_row = start_row.next_row();
15041                }
15042                let end_row =
15043                    if selection.end.row > selection.start.row && selection.end.column == 0 {
15044                        MultiBufferRow(selection.end.row - 1)
15045                    } else {
15046                        MultiBufferRow(selection.end.row)
15047                    };
15048                last_toggled_row = Some(end_row);
15049
15050                if start_row > end_row {
15051                    continue;
15052                }
15053
15054                // If the language has line comments, toggle those.
15055                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
15056
15057                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
15058                if ignore_indent {
15059                    full_comment_prefixes = full_comment_prefixes
15060                        .into_iter()
15061                        .map(|s| Arc::from(s.trim_end()))
15062                        .collect();
15063                }
15064
15065                if !full_comment_prefixes.is_empty() {
15066                    let first_prefix = full_comment_prefixes
15067                        .first()
15068                        .expect("prefixes is non-empty");
15069                    let prefix_trimmed_lengths = full_comment_prefixes
15070                        .iter()
15071                        .map(|p| p.trim_end_matches(' ').len())
15072                        .collect::<SmallVec<[usize; 4]>>();
15073
15074                    let mut all_selection_lines_are_comments = true;
15075
15076                    for row in start_row.0..=end_row.0 {
15077                        let row = MultiBufferRow(row);
15078                        if start_row < end_row && snapshot.is_line_blank(row) {
15079                            continue;
15080                        }
15081
15082                        let prefix_range = full_comment_prefixes
15083                            .iter()
15084                            .zip(prefix_trimmed_lengths.iter().copied())
15085                            .map(|(prefix, trimmed_prefix_len)| {
15086                                comment_prefix_range(
15087                                    snapshot.deref(),
15088                                    row,
15089                                    &prefix[..trimmed_prefix_len],
15090                                    &prefix[trimmed_prefix_len..],
15091                                    ignore_indent,
15092                                )
15093                            })
15094                            .max_by_key(|range| range.end.column - range.start.column)
15095                            .expect("prefixes is non-empty");
15096
15097                        if prefix_range.is_empty() {
15098                            all_selection_lines_are_comments = false;
15099                        }
15100
15101                        selection_edit_ranges.push(prefix_range);
15102                    }
15103
15104                    if all_selection_lines_are_comments {
15105                        edits.extend(
15106                            selection_edit_ranges
15107                                .iter()
15108                                .cloned()
15109                                .map(|range| (range, empty_str.clone())),
15110                        );
15111                    } else {
15112                        let min_column = selection_edit_ranges
15113                            .iter()
15114                            .map(|range| range.start.column)
15115                            .min()
15116                            .unwrap_or(0);
15117                        edits.extend(selection_edit_ranges.iter().map(|range| {
15118                            let position = Point::new(range.start.row, min_column);
15119                            (position..position, first_prefix.clone())
15120                        }));
15121                    }
15122                } else if let Some(BlockCommentConfig {
15123                    start: full_comment_prefix,
15124                    end: comment_suffix,
15125                    ..
15126                }) = language.block_comment()
15127                {
15128                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
15129                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
15130                    let prefix_range = comment_prefix_range(
15131                        snapshot.deref(),
15132                        start_row,
15133                        comment_prefix,
15134                        comment_prefix_whitespace,
15135                        ignore_indent,
15136                    );
15137                    let suffix_range = comment_suffix_range(
15138                        snapshot.deref(),
15139                        end_row,
15140                        comment_suffix.trim_start_matches(' '),
15141                        comment_suffix.starts_with(' '),
15142                    );
15143
15144                    if prefix_range.is_empty() || suffix_range.is_empty() {
15145                        edits.push((
15146                            prefix_range.start..prefix_range.start,
15147                            full_comment_prefix.clone(),
15148                        ));
15149                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
15150                        suffixes_inserted.push((end_row, comment_suffix.len()));
15151                    } else {
15152                        edits.push((prefix_range, empty_str.clone()));
15153                        edits.push((suffix_range, empty_str.clone()));
15154                    }
15155                } else {
15156                    continue;
15157                }
15158            }
15159
15160            drop(snapshot);
15161            this.buffer.update(cx, |buffer, cx| {
15162                buffer.edit(edits, None, cx);
15163            });
15164
15165            // Adjust selections so that they end before any comment suffixes that
15166            // were inserted.
15167            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
15168            let mut selections = this.selections.all::<Point>(&this.display_snapshot(cx));
15169            let snapshot = this.buffer.read(cx).read(cx);
15170            for selection in &mut selections {
15171                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
15172                    match row.cmp(&MultiBufferRow(selection.end.row)) {
15173                        Ordering::Less => {
15174                            suffixes_inserted.next();
15175                            continue;
15176                        }
15177                        Ordering::Greater => break,
15178                        Ordering::Equal => {
15179                            if selection.end.column == snapshot.line_len(row) {
15180                                if selection.is_empty() {
15181                                    selection.start.column -= suffix_len as u32;
15182                                }
15183                                selection.end.column -= suffix_len as u32;
15184                            }
15185                            break;
15186                        }
15187                    }
15188                }
15189            }
15190
15191            drop(snapshot);
15192            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
15193
15194            let selections = this.selections.all::<Point>(&this.display_snapshot(cx));
15195            let selections_on_single_row = selections.windows(2).all(|selections| {
15196                selections[0].start.row == selections[1].start.row
15197                    && selections[0].end.row == selections[1].end.row
15198                    && selections[0].start.row == selections[0].end.row
15199            });
15200            let selections_selecting = selections
15201                .iter()
15202                .any(|selection| selection.start != selection.end);
15203            let advance_downwards = action.advance_downwards
15204                && selections_on_single_row
15205                && !selections_selecting
15206                && !matches!(this.mode, EditorMode::SingleLine);
15207
15208            if advance_downwards {
15209                let snapshot = this.buffer.read(cx).snapshot(cx);
15210
15211                this.change_selections(Default::default(), window, cx, |s| {
15212                    s.move_cursors_with(|display_snapshot, display_point, _| {
15213                        let mut point = display_point.to_point(display_snapshot);
15214                        point.row += 1;
15215                        point = snapshot.clip_point(point, Bias::Left);
15216                        let display_point = point.to_display_point(display_snapshot);
15217                        let goal = SelectionGoal::HorizontalPosition(
15218                            display_snapshot
15219                                .x_for_display_point(display_point, text_layout_details)
15220                                .into(),
15221                        );
15222                        (display_point, goal)
15223                    })
15224                });
15225            }
15226        });
15227    }
15228
15229    pub fn select_enclosing_symbol(
15230        &mut self,
15231        _: &SelectEnclosingSymbol,
15232        window: &mut Window,
15233        cx: &mut Context<Self>,
15234    ) {
15235        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15236
15237        let buffer = self.buffer.read(cx).snapshot(cx);
15238        let old_selections = self
15239            .selections
15240            .all::<usize>(&self.display_snapshot(cx))
15241            .into_boxed_slice();
15242
15243        fn update_selection(
15244            selection: &Selection<usize>,
15245            buffer_snap: &MultiBufferSnapshot,
15246        ) -> Option<Selection<usize>> {
15247            let cursor = selection.head();
15248            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
15249            for symbol in symbols.iter().rev() {
15250                let start = symbol.range.start.to_offset(buffer_snap);
15251                let end = symbol.range.end.to_offset(buffer_snap);
15252                let new_range = start..end;
15253                if start < selection.start || end > selection.end {
15254                    return Some(Selection {
15255                        id: selection.id,
15256                        start: new_range.start,
15257                        end: new_range.end,
15258                        goal: SelectionGoal::None,
15259                        reversed: selection.reversed,
15260                    });
15261                }
15262            }
15263            None
15264        }
15265
15266        let mut selected_larger_symbol = false;
15267        let new_selections = old_selections
15268            .iter()
15269            .map(|selection| match update_selection(selection, &buffer) {
15270                Some(new_selection) => {
15271                    if new_selection.range() != selection.range() {
15272                        selected_larger_symbol = true;
15273                    }
15274                    new_selection
15275                }
15276                None => selection.clone(),
15277            })
15278            .collect::<Vec<_>>();
15279
15280        if selected_larger_symbol {
15281            self.change_selections(Default::default(), window, cx, |s| {
15282                s.select(new_selections);
15283            });
15284        }
15285    }
15286
15287    pub fn select_larger_syntax_node(
15288        &mut self,
15289        _: &SelectLargerSyntaxNode,
15290        window: &mut Window,
15291        cx: &mut Context<Self>,
15292    ) {
15293        let Some(visible_row_count) = self.visible_row_count() else {
15294            return;
15295        };
15296        let old_selections: Box<[_]> = self
15297            .selections
15298            .all::<usize>(&self.display_snapshot(cx))
15299            .into();
15300        if old_selections.is_empty() {
15301            return;
15302        }
15303
15304        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15305
15306        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15307        let buffer = self.buffer.read(cx).snapshot(cx);
15308
15309        let mut selected_larger_node = false;
15310        let mut new_selections = old_selections
15311            .iter()
15312            .map(|selection| {
15313                let old_range = selection.start..selection.end;
15314
15315                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
15316                    // manually select word at selection
15317                    if ["string_content", "inline"].contains(&node.kind()) {
15318                        let (word_range, _) = buffer.surrounding_word(old_range.start, None);
15319                        // ignore if word is already selected
15320                        if !word_range.is_empty() && old_range != word_range {
15321                            let (last_word_range, _) = buffer.surrounding_word(old_range.end, None);
15322                            // only select word if start and end point belongs to same word
15323                            if word_range == last_word_range {
15324                                selected_larger_node = true;
15325                                return Selection {
15326                                    id: selection.id,
15327                                    start: word_range.start,
15328                                    end: word_range.end,
15329                                    goal: SelectionGoal::None,
15330                                    reversed: selection.reversed,
15331                                };
15332                            }
15333                        }
15334                    }
15335                }
15336
15337                let mut new_range = old_range.clone();
15338                while let Some((node, range)) = buffer.syntax_ancestor(new_range.clone()) {
15339                    new_range = range;
15340                    if !node.is_named() {
15341                        continue;
15342                    }
15343                    if !display_map.intersects_fold(new_range.start)
15344                        && !display_map.intersects_fold(new_range.end)
15345                    {
15346                        break;
15347                    }
15348                }
15349
15350                selected_larger_node |= new_range != old_range;
15351                Selection {
15352                    id: selection.id,
15353                    start: new_range.start,
15354                    end: new_range.end,
15355                    goal: SelectionGoal::None,
15356                    reversed: selection.reversed,
15357                }
15358            })
15359            .collect::<Vec<_>>();
15360
15361        if !selected_larger_node {
15362            return; // don't put this call in the history
15363        }
15364
15365        // scroll based on transformation done to the last selection created by the user
15366        let (last_old, last_new) = old_selections
15367            .last()
15368            .zip(new_selections.last().cloned())
15369            .expect("old_selections isn't empty");
15370
15371        // revert selection
15372        let is_selection_reversed = {
15373            let should_newest_selection_be_reversed = last_old.start != last_new.start;
15374            new_selections.last_mut().expect("checked above").reversed =
15375                should_newest_selection_be_reversed;
15376            should_newest_selection_be_reversed
15377        };
15378
15379        if selected_larger_node {
15380            self.select_syntax_node_history.disable_clearing = true;
15381            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15382                s.select(new_selections.clone());
15383            });
15384            self.select_syntax_node_history.disable_clearing = false;
15385        }
15386
15387        let start_row = last_new.start.to_display_point(&display_map).row().0;
15388        let end_row = last_new.end.to_display_point(&display_map).row().0;
15389        let selection_height = end_row - start_row + 1;
15390        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
15391
15392        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
15393        let scroll_behavior = if fits_on_the_screen {
15394            self.request_autoscroll(Autoscroll::fit(), cx);
15395            SelectSyntaxNodeScrollBehavior::FitSelection
15396        } else if is_selection_reversed {
15397            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15398            SelectSyntaxNodeScrollBehavior::CursorTop
15399        } else {
15400            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15401            SelectSyntaxNodeScrollBehavior::CursorBottom
15402        };
15403
15404        self.select_syntax_node_history.push((
15405            old_selections,
15406            scroll_behavior,
15407            is_selection_reversed,
15408        ));
15409    }
15410
15411    pub fn select_smaller_syntax_node(
15412        &mut self,
15413        _: &SelectSmallerSyntaxNode,
15414        window: &mut Window,
15415        cx: &mut Context<Self>,
15416    ) {
15417        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15418
15419        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
15420            self.select_syntax_node_history.pop()
15421        {
15422            if let Some(selection) = selections.last_mut() {
15423                selection.reversed = is_selection_reversed;
15424            }
15425
15426            self.select_syntax_node_history.disable_clearing = true;
15427            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15428                s.select(selections.to_vec());
15429            });
15430            self.select_syntax_node_history.disable_clearing = false;
15431
15432            match scroll_behavior {
15433                SelectSyntaxNodeScrollBehavior::CursorTop => {
15434                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15435                }
15436                SelectSyntaxNodeScrollBehavior::FitSelection => {
15437                    self.request_autoscroll(Autoscroll::fit(), cx);
15438                }
15439                SelectSyntaxNodeScrollBehavior::CursorBottom => {
15440                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15441                }
15442            }
15443        }
15444    }
15445
15446    pub fn unwrap_syntax_node(
15447        &mut self,
15448        _: &UnwrapSyntaxNode,
15449        window: &mut Window,
15450        cx: &mut Context<Self>,
15451    ) {
15452        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15453
15454        let buffer = self.buffer.read(cx).snapshot(cx);
15455        let selections = self
15456            .selections
15457            .all::<usize>(&self.display_snapshot(cx))
15458            .into_iter()
15459            // subtracting the offset requires sorting
15460            .sorted_by_key(|i| i.start);
15461
15462        let full_edits = selections
15463            .into_iter()
15464            .filter_map(|selection| {
15465                let child = if selection.is_empty()
15466                    && let Some((_, ancestor_range)) =
15467                        buffer.syntax_ancestor(selection.start..selection.end)
15468                {
15469                    ancestor_range
15470                } else {
15471                    selection.range()
15472                };
15473
15474                let mut parent = child.clone();
15475                while let Some((_, ancestor_range)) = buffer.syntax_ancestor(parent.clone()) {
15476                    parent = ancestor_range;
15477                    if parent.start < child.start || parent.end > child.end {
15478                        break;
15479                    }
15480                }
15481
15482                if parent == child {
15483                    return None;
15484                }
15485                let text = buffer.text_for_range(child).collect::<String>();
15486                Some((selection.id, parent, text))
15487            })
15488            .collect::<Vec<_>>();
15489        if full_edits.is_empty() {
15490            return;
15491        }
15492
15493        self.transact(window, cx, |this, window, cx| {
15494            this.buffer.update(cx, |buffer, cx| {
15495                buffer.edit(
15496                    full_edits
15497                        .iter()
15498                        .map(|(_, p, t)| (p.clone(), t.clone()))
15499                        .collect::<Vec<_>>(),
15500                    None,
15501                    cx,
15502                );
15503            });
15504            this.change_selections(Default::default(), window, cx, |s| {
15505                let mut offset = 0;
15506                let mut selections = vec![];
15507                for (id, parent, text) in full_edits {
15508                    let start = parent.start - offset;
15509                    offset += parent.len() - text.len();
15510                    selections.push(Selection {
15511                        id,
15512                        start,
15513                        end: start + text.len(),
15514                        reversed: false,
15515                        goal: Default::default(),
15516                    });
15517                }
15518                s.select(selections);
15519            });
15520        });
15521    }
15522
15523    pub fn select_next_syntax_node(
15524        &mut self,
15525        _: &SelectNextSyntaxNode,
15526        window: &mut Window,
15527        cx: &mut Context<Self>,
15528    ) {
15529        let old_selections: Box<[_]> = self
15530            .selections
15531            .all::<usize>(&self.display_snapshot(cx))
15532            .into();
15533        if old_selections.is_empty() {
15534            return;
15535        }
15536
15537        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15538
15539        let buffer = self.buffer.read(cx).snapshot(cx);
15540        let mut selected_sibling = false;
15541
15542        let new_selections = old_selections
15543            .iter()
15544            .map(|selection| {
15545                let old_range = selection.start..selection.end;
15546
15547                if let Some(node) = buffer.syntax_next_sibling(old_range) {
15548                    let new_range = node.byte_range();
15549                    selected_sibling = true;
15550                    Selection {
15551                        id: selection.id,
15552                        start: new_range.start,
15553                        end: new_range.end,
15554                        goal: SelectionGoal::None,
15555                        reversed: selection.reversed,
15556                    }
15557                } else {
15558                    selection.clone()
15559                }
15560            })
15561            .collect::<Vec<_>>();
15562
15563        if selected_sibling {
15564            self.change_selections(
15565                SelectionEffects::scroll(Autoscroll::fit()),
15566                window,
15567                cx,
15568                |s| {
15569                    s.select(new_selections);
15570                },
15571            );
15572        }
15573    }
15574
15575    pub fn select_prev_syntax_node(
15576        &mut self,
15577        _: &SelectPreviousSyntaxNode,
15578        window: &mut Window,
15579        cx: &mut Context<Self>,
15580    ) {
15581        let old_selections: Box<[_]> = self
15582            .selections
15583            .all::<usize>(&self.display_snapshot(cx))
15584            .into();
15585        if old_selections.is_empty() {
15586            return;
15587        }
15588
15589        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15590
15591        let buffer = self.buffer.read(cx).snapshot(cx);
15592        let mut selected_sibling = false;
15593
15594        let new_selections = old_selections
15595            .iter()
15596            .map(|selection| {
15597                let old_range = selection.start..selection.end;
15598
15599                if let Some(node) = buffer.syntax_prev_sibling(old_range) {
15600                    let new_range = node.byte_range();
15601                    selected_sibling = true;
15602                    Selection {
15603                        id: selection.id,
15604                        start: new_range.start,
15605                        end: new_range.end,
15606                        goal: SelectionGoal::None,
15607                        reversed: selection.reversed,
15608                    }
15609                } else {
15610                    selection.clone()
15611                }
15612            })
15613            .collect::<Vec<_>>();
15614
15615        if selected_sibling {
15616            self.change_selections(
15617                SelectionEffects::scroll(Autoscroll::fit()),
15618                window,
15619                cx,
15620                |s| {
15621                    s.select(new_selections);
15622                },
15623            );
15624        }
15625    }
15626
15627    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
15628        if !EditorSettings::get_global(cx).gutter.runnables {
15629            self.clear_tasks();
15630            return Task::ready(());
15631        }
15632        let project = self.project().map(Entity::downgrade);
15633        let task_sources = self.lsp_task_sources(cx);
15634        let multi_buffer = self.buffer.downgrade();
15635        cx.spawn_in(window, async move |editor, cx| {
15636            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
15637            let Some(project) = project.and_then(|p| p.upgrade()) else {
15638                return;
15639            };
15640            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
15641                this.display_map.update(cx, |map, cx| map.snapshot(cx))
15642            }) else {
15643                return;
15644            };
15645
15646            let hide_runnables = project
15647                .update(cx, |project, _| project.is_via_collab())
15648                .unwrap_or(true);
15649            if hide_runnables {
15650                return;
15651            }
15652            let new_rows =
15653                cx.background_spawn({
15654                    let snapshot = display_snapshot.clone();
15655                    async move {
15656                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
15657                    }
15658                })
15659                    .await;
15660            let Ok(lsp_tasks) =
15661                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
15662            else {
15663                return;
15664            };
15665            let lsp_tasks = lsp_tasks.await;
15666
15667            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
15668                lsp_tasks
15669                    .into_iter()
15670                    .flat_map(|(kind, tasks)| {
15671                        tasks.into_iter().filter_map(move |(location, task)| {
15672                            Some((kind.clone(), location?, task))
15673                        })
15674                    })
15675                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
15676                        let buffer = location.target.buffer;
15677                        let buffer_snapshot = buffer.read(cx).snapshot();
15678                        let offset = display_snapshot.buffer_snapshot().excerpts().find_map(
15679                            |(excerpt_id, snapshot, _)| {
15680                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
15681                                    display_snapshot
15682                                        .buffer_snapshot()
15683                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
15684                                } else {
15685                                    None
15686                                }
15687                            },
15688                        );
15689                        if let Some(offset) = offset {
15690                            let task_buffer_range =
15691                                location.target.range.to_point(&buffer_snapshot);
15692                            let context_buffer_range =
15693                                task_buffer_range.to_offset(&buffer_snapshot);
15694                            let context_range = BufferOffset(context_buffer_range.start)
15695                                ..BufferOffset(context_buffer_range.end);
15696
15697                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
15698                                .or_insert_with(|| RunnableTasks {
15699                                    templates: Vec::new(),
15700                                    offset,
15701                                    column: task_buffer_range.start.column,
15702                                    extra_variables: HashMap::default(),
15703                                    context_range,
15704                                })
15705                                .templates
15706                                .push((kind, task.original_task().clone()));
15707                        }
15708
15709                        acc
15710                    })
15711            }) else {
15712                return;
15713            };
15714
15715            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
15716                buffer.language_settings(cx).tasks.prefer_lsp
15717            }) else {
15718                return;
15719            };
15720
15721            let rows = Self::runnable_rows(
15722                project,
15723                display_snapshot,
15724                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
15725                new_rows,
15726                cx.clone(),
15727            )
15728            .await;
15729            editor
15730                .update(cx, |editor, _| {
15731                    editor.clear_tasks();
15732                    for (key, mut value) in rows {
15733                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
15734                            value.templates.extend(lsp_tasks.templates);
15735                        }
15736
15737                        editor.insert_tasks(key, value);
15738                    }
15739                    for (key, value) in lsp_tasks_by_rows {
15740                        editor.insert_tasks(key, value);
15741                    }
15742                })
15743                .ok();
15744        })
15745    }
15746    fn fetch_runnable_ranges(
15747        snapshot: &DisplaySnapshot,
15748        range: Range<Anchor>,
15749    ) -> Vec<language::RunnableRange> {
15750        snapshot.buffer_snapshot().runnable_ranges(range).collect()
15751    }
15752
15753    fn runnable_rows(
15754        project: Entity<Project>,
15755        snapshot: DisplaySnapshot,
15756        prefer_lsp: bool,
15757        runnable_ranges: Vec<RunnableRange>,
15758        cx: AsyncWindowContext,
15759    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
15760        cx.spawn(async move |cx| {
15761            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
15762            for mut runnable in runnable_ranges {
15763                let Some(tasks) = cx
15764                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
15765                    .ok()
15766                else {
15767                    continue;
15768                };
15769                let mut tasks = tasks.await;
15770
15771                if prefer_lsp {
15772                    tasks.retain(|(task_kind, _)| {
15773                        !matches!(task_kind, TaskSourceKind::Language { .. })
15774                    });
15775                }
15776                if tasks.is_empty() {
15777                    continue;
15778                }
15779
15780                let point = runnable
15781                    .run_range
15782                    .start
15783                    .to_point(&snapshot.buffer_snapshot());
15784                let Some(row) = snapshot
15785                    .buffer_snapshot()
15786                    .buffer_line_for_row(MultiBufferRow(point.row))
15787                    .map(|(_, range)| range.start.row)
15788                else {
15789                    continue;
15790                };
15791
15792                let context_range =
15793                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
15794                runnable_rows.push((
15795                    (runnable.buffer_id, row),
15796                    RunnableTasks {
15797                        templates: tasks,
15798                        offset: snapshot
15799                            .buffer_snapshot()
15800                            .anchor_before(runnable.run_range.start),
15801                        context_range,
15802                        column: point.column,
15803                        extra_variables: runnable.extra_captures,
15804                    },
15805                ));
15806            }
15807            runnable_rows
15808        })
15809    }
15810
15811    fn templates_with_tags(
15812        project: &Entity<Project>,
15813        runnable: &mut Runnable,
15814        cx: &mut App,
15815    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
15816        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
15817            let (worktree_id, file) = project
15818                .buffer_for_id(runnable.buffer, cx)
15819                .and_then(|buffer| buffer.read(cx).file())
15820                .map(|file| (file.worktree_id(cx), file.clone()))
15821                .unzip();
15822
15823            (
15824                project.task_store().read(cx).task_inventory().cloned(),
15825                worktree_id,
15826                file,
15827            )
15828        });
15829
15830        let tags = mem::take(&mut runnable.tags);
15831        let language = runnable.language.clone();
15832        cx.spawn(async move |cx| {
15833            let mut templates_with_tags = Vec::new();
15834            if let Some(inventory) = inventory {
15835                for RunnableTag(tag) in tags {
15836                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
15837                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
15838                    }) else {
15839                        return templates_with_tags;
15840                    };
15841                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
15842                        move |(_, template)| {
15843                            template.tags.iter().any(|source_tag| source_tag == &tag)
15844                        },
15845                    ));
15846                }
15847            }
15848            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
15849
15850            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
15851                // Strongest source wins; if we have worktree tag binding, prefer that to
15852                // global and language bindings;
15853                // if we have a global binding, prefer that to language binding.
15854                let first_mismatch = templates_with_tags
15855                    .iter()
15856                    .position(|(tag_source, _)| tag_source != leading_tag_source);
15857                if let Some(index) = first_mismatch {
15858                    templates_with_tags.truncate(index);
15859                }
15860            }
15861
15862            templates_with_tags
15863        })
15864    }
15865
15866    pub fn move_to_enclosing_bracket(
15867        &mut self,
15868        _: &MoveToEnclosingBracket,
15869        window: &mut Window,
15870        cx: &mut Context<Self>,
15871    ) {
15872        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15873        self.change_selections(Default::default(), window, cx, |s| {
15874            s.move_offsets_with(|snapshot, selection| {
15875                let Some(enclosing_bracket_ranges) =
15876                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
15877                else {
15878                    return;
15879                };
15880
15881                let mut best_length = usize::MAX;
15882                let mut best_inside = false;
15883                let mut best_in_bracket_range = false;
15884                let mut best_destination = None;
15885                for (open, close) in enclosing_bracket_ranges {
15886                    let close = close.to_inclusive();
15887                    let length = close.end() - open.start;
15888                    let inside = selection.start >= open.end && selection.end <= *close.start();
15889                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
15890                        || close.contains(&selection.head());
15891
15892                    // If best is next to a bracket and current isn't, skip
15893                    if !in_bracket_range && best_in_bracket_range {
15894                        continue;
15895                    }
15896
15897                    // Prefer smaller lengths unless best is inside and current isn't
15898                    if length > best_length && (best_inside || !inside) {
15899                        continue;
15900                    }
15901
15902                    best_length = length;
15903                    best_inside = inside;
15904                    best_in_bracket_range = in_bracket_range;
15905                    best_destination = Some(
15906                        if close.contains(&selection.start) && close.contains(&selection.end) {
15907                            if inside { open.end } else { open.start }
15908                        } else if inside {
15909                            *close.start()
15910                        } else {
15911                            *close.end()
15912                        },
15913                    );
15914                }
15915
15916                if let Some(destination) = best_destination {
15917                    selection.collapse_to(destination, SelectionGoal::None);
15918                }
15919            })
15920        });
15921    }
15922
15923    pub fn undo_selection(
15924        &mut self,
15925        _: &UndoSelection,
15926        window: &mut Window,
15927        cx: &mut Context<Self>,
15928    ) {
15929        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15930        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
15931            self.selection_history.mode = SelectionHistoryMode::Undoing;
15932            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15933                this.end_selection(window, cx);
15934                this.change_selections(
15935                    SelectionEffects::scroll(Autoscroll::newest()),
15936                    window,
15937                    cx,
15938                    |s| s.select_anchors(entry.selections.to_vec()),
15939                );
15940            });
15941            self.selection_history.mode = SelectionHistoryMode::Normal;
15942
15943            self.select_next_state = entry.select_next_state;
15944            self.select_prev_state = entry.select_prev_state;
15945            self.add_selections_state = entry.add_selections_state;
15946        }
15947    }
15948
15949    pub fn redo_selection(
15950        &mut self,
15951        _: &RedoSelection,
15952        window: &mut Window,
15953        cx: &mut Context<Self>,
15954    ) {
15955        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15956        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
15957            self.selection_history.mode = SelectionHistoryMode::Redoing;
15958            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15959                this.end_selection(window, cx);
15960                this.change_selections(
15961                    SelectionEffects::scroll(Autoscroll::newest()),
15962                    window,
15963                    cx,
15964                    |s| s.select_anchors(entry.selections.to_vec()),
15965                );
15966            });
15967            self.selection_history.mode = SelectionHistoryMode::Normal;
15968
15969            self.select_next_state = entry.select_next_state;
15970            self.select_prev_state = entry.select_prev_state;
15971            self.add_selections_state = entry.add_selections_state;
15972        }
15973    }
15974
15975    pub fn expand_excerpts(
15976        &mut self,
15977        action: &ExpandExcerpts,
15978        _: &mut Window,
15979        cx: &mut Context<Self>,
15980    ) {
15981        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
15982    }
15983
15984    pub fn expand_excerpts_down(
15985        &mut self,
15986        action: &ExpandExcerptsDown,
15987        _: &mut Window,
15988        cx: &mut Context<Self>,
15989    ) {
15990        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
15991    }
15992
15993    pub fn expand_excerpts_up(
15994        &mut self,
15995        action: &ExpandExcerptsUp,
15996        _: &mut Window,
15997        cx: &mut Context<Self>,
15998    ) {
15999        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
16000    }
16001
16002    pub fn expand_excerpts_for_direction(
16003        &mut self,
16004        lines: u32,
16005        direction: ExpandExcerptDirection,
16006
16007        cx: &mut Context<Self>,
16008    ) {
16009        let selections = self.selections.disjoint_anchors_arc();
16010
16011        let lines = if lines == 0 {
16012            EditorSettings::get_global(cx).expand_excerpt_lines
16013        } else {
16014            lines
16015        };
16016
16017        self.buffer.update(cx, |buffer, cx| {
16018            let snapshot = buffer.snapshot(cx);
16019            let mut excerpt_ids = selections
16020                .iter()
16021                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
16022                .collect::<Vec<_>>();
16023            excerpt_ids.sort();
16024            excerpt_ids.dedup();
16025            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
16026        })
16027    }
16028
16029    pub fn expand_excerpt(
16030        &mut self,
16031        excerpt: ExcerptId,
16032        direction: ExpandExcerptDirection,
16033        window: &mut Window,
16034        cx: &mut Context<Self>,
16035    ) {
16036        let current_scroll_position = self.scroll_position(cx);
16037        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
16038        let mut scroll = None;
16039
16040        if direction == ExpandExcerptDirection::Down {
16041            let multi_buffer = self.buffer.read(cx);
16042            let snapshot = multi_buffer.snapshot(cx);
16043            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt)
16044                && let Some(buffer) = multi_buffer.buffer(buffer_id)
16045                && let Some(excerpt_range) = snapshot.context_range_for_excerpt(excerpt)
16046            {
16047                let buffer_snapshot = buffer.read(cx).snapshot();
16048                let excerpt_end_row = Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
16049                let last_row = buffer_snapshot.max_point().row;
16050                let lines_below = last_row.saturating_sub(excerpt_end_row);
16051                if lines_below >= lines_to_expand {
16052                    scroll = Some(
16053                        current_scroll_position
16054                            + gpui::Point::new(0.0, lines_to_expand as ScrollOffset),
16055                    );
16056                }
16057            }
16058        }
16059        if direction == ExpandExcerptDirection::Up
16060            && self
16061                .buffer
16062                .read(cx)
16063                .snapshot(cx)
16064                .excerpt_before(excerpt)
16065                .is_none()
16066        {
16067            scroll = Some(current_scroll_position);
16068        }
16069
16070        self.buffer.update(cx, |buffer, cx| {
16071            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
16072        });
16073
16074        if let Some(new_scroll_position) = scroll {
16075            self.set_scroll_position(new_scroll_position, window, cx);
16076        }
16077    }
16078
16079    pub fn go_to_singleton_buffer_point(
16080        &mut self,
16081        point: Point,
16082        window: &mut Window,
16083        cx: &mut Context<Self>,
16084    ) {
16085        self.go_to_singleton_buffer_range(point..point, window, cx);
16086    }
16087
16088    pub fn go_to_singleton_buffer_range(
16089        &mut self,
16090        range: Range<Point>,
16091        window: &mut Window,
16092        cx: &mut Context<Self>,
16093    ) {
16094        let multibuffer = self.buffer().read(cx);
16095        let Some(buffer) = multibuffer.as_singleton() else {
16096            return;
16097        };
16098        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
16099            return;
16100        };
16101        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
16102            return;
16103        };
16104        self.change_selections(
16105            SelectionEffects::default().nav_history(true),
16106            window,
16107            cx,
16108            |s| s.select_anchor_ranges([start..end]),
16109        );
16110    }
16111
16112    pub fn go_to_diagnostic(
16113        &mut self,
16114        action: &GoToDiagnostic,
16115        window: &mut Window,
16116        cx: &mut Context<Self>,
16117    ) {
16118        if !self.diagnostics_enabled() {
16119            return;
16120        }
16121        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16122        self.go_to_diagnostic_impl(Direction::Next, action.severity, window, cx)
16123    }
16124
16125    pub fn go_to_prev_diagnostic(
16126        &mut self,
16127        action: &GoToPreviousDiagnostic,
16128        window: &mut Window,
16129        cx: &mut Context<Self>,
16130    ) {
16131        if !self.diagnostics_enabled() {
16132            return;
16133        }
16134        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16135        self.go_to_diagnostic_impl(Direction::Prev, action.severity, window, cx)
16136    }
16137
16138    pub fn go_to_diagnostic_impl(
16139        &mut self,
16140        direction: Direction,
16141        severity: GoToDiagnosticSeverityFilter,
16142        window: &mut Window,
16143        cx: &mut Context<Self>,
16144    ) {
16145        let buffer = self.buffer.read(cx).snapshot(cx);
16146        let selection = self.selections.newest::<usize>(&self.display_snapshot(cx));
16147
16148        let mut active_group_id = None;
16149        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics
16150            && active_group.active_range.start.to_offset(&buffer) == selection.start
16151        {
16152            active_group_id = Some(active_group.group_id);
16153        }
16154
16155        fn filtered<'a>(
16156            severity: GoToDiagnosticSeverityFilter,
16157            diagnostics: impl Iterator<Item = DiagnosticEntryRef<'a, usize>>,
16158        ) -> impl Iterator<Item = DiagnosticEntryRef<'a, usize>> {
16159            diagnostics
16160                .filter(move |entry| severity.matches(entry.diagnostic.severity))
16161                .filter(|entry| entry.range.start != entry.range.end)
16162                .filter(|entry| !entry.diagnostic.is_unnecessary)
16163        }
16164
16165        let before = filtered(
16166            severity,
16167            buffer
16168                .diagnostics_in_range(0..selection.start)
16169                .filter(|entry| entry.range.start <= selection.start),
16170        );
16171        let after = filtered(
16172            severity,
16173            buffer
16174                .diagnostics_in_range(selection.start..buffer.len())
16175                .filter(|entry| entry.range.start >= selection.start),
16176        );
16177
16178        let mut found: Option<DiagnosticEntryRef<usize>> = None;
16179        if direction == Direction::Prev {
16180            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
16181            {
16182                for diagnostic in prev_diagnostics.into_iter().rev() {
16183                    if diagnostic.range.start != selection.start
16184                        || active_group_id
16185                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
16186                    {
16187                        found = Some(diagnostic);
16188                        break 'outer;
16189                    }
16190                }
16191            }
16192        } else {
16193            for diagnostic in after.chain(before) {
16194                if diagnostic.range.start != selection.start
16195                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
16196                {
16197                    found = Some(diagnostic);
16198                    break;
16199                }
16200            }
16201        }
16202        let Some(next_diagnostic) = found else {
16203            return;
16204        };
16205
16206        let next_diagnostic_start = buffer.anchor_after(next_diagnostic.range.start);
16207        let Some(buffer_id) = buffer.buffer_id_for_anchor(next_diagnostic_start) else {
16208            return;
16209        };
16210        let snapshot = self.snapshot(window, cx);
16211        if snapshot.intersects_fold(next_diagnostic.range.start) {
16212            self.unfold_ranges(
16213                std::slice::from_ref(&next_diagnostic.range),
16214                true,
16215                false,
16216                cx,
16217            );
16218        }
16219        self.change_selections(Default::default(), window, cx, |s| {
16220            s.select_ranges(vec![
16221                next_diagnostic.range.start..next_diagnostic.range.start,
16222            ])
16223        });
16224        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
16225        self.refresh_edit_prediction(false, true, window, cx);
16226    }
16227
16228    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
16229        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16230        let snapshot = self.snapshot(window, cx);
16231        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
16232        self.go_to_hunk_before_or_after_position(
16233            &snapshot,
16234            selection.head(),
16235            Direction::Next,
16236            window,
16237            cx,
16238        );
16239    }
16240
16241    pub fn go_to_hunk_before_or_after_position(
16242        &mut self,
16243        snapshot: &EditorSnapshot,
16244        position: Point,
16245        direction: Direction,
16246        window: &mut Window,
16247        cx: &mut Context<Editor>,
16248    ) {
16249        let row = if direction == Direction::Next {
16250            self.hunk_after_position(snapshot, position)
16251                .map(|hunk| hunk.row_range.start)
16252        } else {
16253            self.hunk_before_position(snapshot, position)
16254        };
16255
16256        if let Some(row) = row {
16257            let destination = Point::new(row.0, 0);
16258            let autoscroll = Autoscroll::center();
16259
16260            self.unfold_ranges(&[destination..destination], false, false, cx);
16261            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16262                s.select_ranges([destination..destination]);
16263            });
16264        }
16265    }
16266
16267    fn hunk_after_position(
16268        &mut self,
16269        snapshot: &EditorSnapshot,
16270        position: Point,
16271    ) -> Option<MultiBufferDiffHunk> {
16272        snapshot
16273            .buffer_snapshot()
16274            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
16275            .find(|hunk| hunk.row_range.start.0 > position.row)
16276            .or_else(|| {
16277                snapshot
16278                    .buffer_snapshot()
16279                    .diff_hunks_in_range(Point::zero()..position)
16280                    .find(|hunk| hunk.row_range.end.0 < position.row)
16281            })
16282    }
16283
16284    fn go_to_prev_hunk(
16285        &mut self,
16286        _: &GoToPreviousHunk,
16287        window: &mut Window,
16288        cx: &mut Context<Self>,
16289    ) {
16290        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16291        let snapshot = self.snapshot(window, cx);
16292        let selection = self.selections.newest::<Point>(&snapshot.display_snapshot);
16293        self.go_to_hunk_before_or_after_position(
16294            &snapshot,
16295            selection.head(),
16296            Direction::Prev,
16297            window,
16298            cx,
16299        );
16300    }
16301
16302    fn hunk_before_position(
16303        &mut self,
16304        snapshot: &EditorSnapshot,
16305        position: Point,
16306    ) -> Option<MultiBufferRow> {
16307        snapshot
16308            .buffer_snapshot()
16309            .diff_hunk_before(position)
16310            .or_else(|| snapshot.buffer_snapshot().diff_hunk_before(Point::MAX))
16311    }
16312
16313    fn go_to_next_change(
16314        &mut self,
16315        _: &GoToNextChange,
16316        window: &mut Window,
16317        cx: &mut Context<Self>,
16318    ) {
16319        if let Some(selections) = self
16320            .change_list
16321            .next_change(1, Direction::Next)
16322            .map(|s| s.to_vec())
16323        {
16324            self.change_selections(Default::default(), window, cx, |s| {
16325                let map = s.display_snapshot();
16326                s.select_display_ranges(selections.iter().map(|a| {
16327                    let point = a.to_display_point(&map);
16328                    point..point
16329                }))
16330            })
16331        }
16332    }
16333
16334    fn go_to_previous_change(
16335        &mut self,
16336        _: &GoToPreviousChange,
16337        window: &mut Window,
16338        cx: &mut Context<Self>,
16339    ) {
16340        if let Some(selections) = self
16341            .change_list
16342            .next_change(1, Direction::Prev)
16343            .map(|s| s.to_vec())
16344        {
16345            self.change_selections(Default::default(), window, cx, |s| {
16346                let map = s.display_snapshot();
16347                s.select_display_ranges(selections.iter().map(|a| {
16348                    let point = a.to_display_point(&map);
16349                    point..point
16350                }))
16351            })
16352        }
16353    }
16354
16355    pub fn go_to_next_document_highlight(
16356        &mut self,
16357        _: &GoToNextDocumentHighlight,
16358        window: &mut Window,
16359        cx: &mut Context<Self>,
16360    ) {
16361        self.go_to_document_highlight_before_or_after_position(Direction::Next, window, cx);
16362    }
16363
16364    pub fn go_to_prev_document_highlight(
16365        &mut self,
16366        _: &GoToPreviousDocumentHighlight,
16367        window: &mut Window,
16368        cx: &mut Context<Self>,
16369    ) {
16370        self.go_to_document_highlight_before_or_after_position(Direction::Prev, window, cx);
16371    }
16372
16373    pub fn go_to_document_highlight_before_or_after_position(
16374        &mut self,
16375        direction: Direction,
16376        window: &mut Window,
16377        cx: &mut Context<Editor>,
16378    ) {
16379        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16380        let snapshot = self.snapshot(window, cx);
16381        let buffer = &snapshot.buffer_snapshot();
16382        let position = self
16383            .selections
16384            .newest::<Point>(&snapshot.display_snapshot)
16385            .head();
16386        let anchor_position = buffer.anchor_after(position);
16387
16388        // Get all document highlights (both read and write)
16389        let mut all_highlights = Vec::new();
16390
16391        if let Some((_, read_highlights)) = self
16392            .background_highlights
16393            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
16394        {
16395            all_highlights.extend(read_highlights.iter());
16396        }
16397
16398        if let Some((_, write_highlights)) = self
16399            .background_highlights
16400            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
16401        {
16402            all_highlights.extend(write_highlights.iter());
16403        }
16404
16405        if all_highlights.is_empty() {
16406            return;
16407        }
16408
16409        // Sort highlights by position
16410        all_highlights.sort_by(|a, b| a.start.cmp(&b.start, buffer));
16411
16412        let target_highlight = match direction {
16413            Direction::Next => {
16414                // Find the first highlight after the current position
16415                all_highlights
16416                    .iter()
16417                    .find(|highlight| highlight.start.cmp(&anchor_position, buffer).is_gt())
16418            }
16419            Direction::Prev => {
16420                // Find the last highlight before the current position
16421                all_highlights
16422                    .iter()
16423                    .rev()
16424                    .find(|highlight| highlight.end.cmp(&anchor_position, buffer).is_lt())
16425            }
16426        };
16427
16428        if let Some(highlight) = target_highlight {
16429            let destination = highlight.start.to_point(buffer);
16430            let autoscroll = Autoscroll::center();
16431
16432            self.unfold_ranges(&[destination..destination], false, false, cx);
16433            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16434                s.select_ranges([destination..destination]);
16435            });
16436        }
16437    }
16438
16439    fn go_to_line<T: 'static>(
16440        &mut self,
16441        position: Anchor,
16442        highlight_color: Option<Hsla>,
16443        window: &mut Window,
16444        cx: &mut Context<Self>,
16445    ) {
16446        let snapshot = self.snapshot(window, cx).display_snapshot;
16447        let position = position.to_point(&snapshot.buffer_snapshot());
16448        let start = snapshot
16449            .buffer_snapshot()
16450            .clip_point(Point::new(position.row, 0), Bias::Left);
16451        let end = start + Point::new(1, 0);
16452        let start = snapshot.buffer_snapshot().anchor_before(start);
16453        let end = snapshot.buffer_snapshot().anchor_before(end);
16454
16455        self.highlight_rows::<T>(
16456            start..end,
16457            highlight_color
16458                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
16459            Default::default(),
16460            cx,
16461        );
16462
16463        if self.buffer.read(cx).is_singleton() {
16464            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
16465        }
16466    }
16467
16468    pub fn go_to_definition(
16469        &mut self,
16470        _: &GoToDefinition,
16471        window: &mut Window,
16472        cx: &mut Context<Self>,
16473    ) -> Task<Result<Navigated>> {
16474        let definition =
16475            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
16476        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
16477        cx.spawn_in(window, async move |editor, cx| {
16478            if definition.await? == Navigated::Yes {
16479                return Ok(Navigated::Yes);
16480            }
16481            match fallback_strategy {
16482                GoToDefinitionFallback::None => Ok(Navigated::No),
16483                GoToDefinitionFallback::FindAllReferences => {
16484                    match editor.update_in(cx, |editor, window, cx| {
16485                        editor.find_all_references(&FindAllReferences, window, cx)
16486                    })? {
16487                        Some(references) => references.await,
16488                        None => Ok(Navigated::No),
16489                    }
16490                }
16491            }
16492        })
16493    }
16494
16495    pub fn go_to_declaration(
16496        &mut self,
16497        _: &GoToDeclaration,
16498        window: &mut Window,
16499        cx: &mut Context<Self>,
16500    ) -> Task<Result<Navigated>> {
16501        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
16502    }
16503
16504    pub fn go_to_declaration_split(
16505        &mut self,
16506        _: &GoToDeclaration,
16507        window: &mut Window,
16508        cx: &mut Context<Self>,
16509    ) -> Task<Result<Navigated>> {
16510        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
16511    }
16512
16513    pub fn go_to_implementation(
16514        &mut self,
16515        _: &GoToImplementation,
16516        window: &mut Window,
16517        cx: &mut Context<Self>,
16518    ) -> Task<Result<Navigated>> {
16519        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
16520    }
16521
16522    pub fn go_to_implementation_split(
16523        &mut self,
16524        _: &GoToImplementationSplit,
16525        window: &mut Window,
16526        cx: &mut Context<Self>,
16527    ) -> Task<Result<Navigated>> {
16528        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
16529    }
16530
16531    pub fn go_to_type_definition(
16532        &mut self,
16533        _: &GoToTypeDefinition,
16534        window: &mut Window,
16535        cx: &mut Context<Self>,
16536    ) -> Task<Result<Navigated>> {
16537        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
16538    }
16539
16540    pub fn go_to_definition_split(
16541        &mut self,
16542        _: &GoToDefinitionSplit,
16543        window: &mut Window,
16544        cx: &mut Context<Self>,
16545    ) -> Task<Result<Navigated>> {
16546        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
16547    }
16548
16549    pub fn go_to_type_definition_split(
16550        &mut self,
16551        _: &GoToTypeDefinitionSplit,
16552        window: &mut Window,
16553        cx: &mut Context<Self>,
16554    ) -> Task<Result<Navigated>> {
16555        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
16556    }
16557
16558    fn go_to_definition_of_kind(
16559        &mut self,
16560        kind: GotoDefinitionKind,
16561        split: bool,
16562        window: &mut Window,
16563        cx: &mut Context<Self>,
16564    ) -> Task<Result<Navigated>> {
16565        let Some(provider) = self.semantics_provider.clone() else {
16566            return Task::ready(Ok(Navigated::No));
16567        };
16568        let head = self
16569            .selections
16570            .newest::<usize>(&self.display_snapshot(cx))
16571            .head();
16572        let buffer = self.buffer.read(cx);
16573        let Some((buffer, head)) = buffer.text_anchor_for_position(head, cx) else {
16574            return Task::ready(Ok(Navigated::No));
16575        };
16576        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
16577            return Task::ready(Ok(Navigated::No));
16578        };
16579
16580        cx.spawn_in(window, async move |editor, cx| {
16581            let Some(definitions) = definitions.await? else {
16582                return Ok(Navigated::No);
16583            };
16584            let navigated = editor
16585                .update_in(cx, |editor, window, cx| {
16586                    editor.navigate_to_hover_links(
16587                        Some(kind),
16588                        definitions
16589                            .into_iter()
16590                            .filter(|location| {
16591                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
16592                            })
16593                            .map(HoverLink::Text)
16594                            .collect::<Vec<_>>(),
16595                        split,
16596                        window,
16597                        cx,
16598                    )
16599                })?
16600                .await?;
16601            anyhow::Ok(navigated)
16602        })
16603    }
16604
16605    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
16606        let selection = self.selections.newest_anchor();
16607        let head = selection.head();
16608        let tail = selection.tail();
16609
16610        let Some((buffer, start_position)) =
16611            self.buffer.read(cx).text_anchor_for_position(head, cx)
16612        else {
16613            return;
16614        };
16615
16616        let end_position = if head != tail {
16617            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
16618                return;
16619            };
16620            Some(pos)
16621        } else {
16622            None
16623        };
16624
16625        let url_finder = cx.spawn_in(window, async move |_editor, cx| {
16626            let url = if let Some(end_pos) = end_position {
16627                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
16628            } else {
16629                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
16630            };
16631
16632            if let Some(url) = url {
16633                cx.update(|window, cx| {
16634                    if parse_zed_link(&url, cx).is_some() {
16635                        window.dispatch_action(Box::new(zed_actions::OpenZedUrl { url }), cx);
16636                    } else {
16637                        cx.open_url(&url);
16638                    }
16639                })?;
16640            }
16641
16642            anyhow::Ok(())
16643        });
16644
16645        url_finder.detach();
16646    }
16647
16648    pub fn open_selected_filename(
16649        &mut self,
16650        _: &OpenSelectedFilename,
16651        window: &mut Window,
16652        cx: &mut Context<Self>,
16653    ) {
16654        let Some(workspace) = self.workspace() else {
16655            return;
16656        };
16657
16658        let position = self.selections.newest_anchor().head();
16659
16660        let Some((buffer, buffer_position)) =
16661            self.buffer.read(cx).text_anchor_for_position(position, cx)
16662        else {
16663            return;
16664        };
16665
16666        let project = self.project.clone();
16667
16668        cx.spawn_in(window, async move |_, cx| {
16669            let result = find_file(&buffer, project, buffer_position, cx).await;
16670
16671            if let Some((_, path)) = result {
16672                workspace
16673                    .update_in(cx, |workspace, window, cx| {
16674                        workspace.open_resolved_path(path, window, cx)
16675                    })?
16676                    .await?;
16677            }
16678            anyhow::Ok(())
16679        })
16680        .detach();
16681    }
16682
16683    pub(crate) fn navigate_to_hover_links(
16684        &mut self,
16685        kind: Option<GotoDefinitionKind>,
16686        definitions: Vec<HoverLink>,
16687        split: bool,
16688        window: &mut Window,
16689        cx: &mut Context<Editor>,
16690    ) -> Task<Result<Navigated>> {
16691        // Separate out url and file links, we can only handle one of them at most or an arbitrary number of locations
16692        let mut first_url_or_file = None;
16693        let definitions: Vec<_> = definitions
16694            .into_iter()
16695            .filter_map(|def| match def {
16696                HoverLink::Text(link) => Some(Task::ready(anyhow::Ok(Some(link.target)))),
16697                HoverLink::InlayHint(lsp_location, server_id) => {
16698                    let computation =
16699                        self.compute_target_location(lsp_location, server_id, window, cx);
16700                    Some(cx.background_spawn(computation))
16701                }
16702                HoverLink::Url(url) => {
16703                    first_url_or_file = Some(Either::Left(url));
16704                    None
16705                }
16706                HoverLink::File(path) => {
16707                    first_url_or_file = Some(Either::Right(path));
16708                    None
16709                }
16710            })
16711            .collect();
16712
16713        let workspace = self.workspace();
16714
16715        cx.spawn_in(window, async move |editor, cx| {
16716            let locations: Vec<Location> = future::join_all(definitions)
16717                .await
16718                .into_iter()
16719                .filter_map(|location| location.transpose())
16720                .collect::<Result<_>>()
16721                .context("location tasks")?;
16722            let mut locations = cx.update(|_, cx| {
16723                locations
16724                    .into_iter()
16725                    .map(|location| {
16726                        let buffer = location.buffer.read(cx);
16727                        (location.buffer, location.range.to_point(buffer))
16728                    })
16729                    .into_group_map()
16730            })?;
16731            let mut num_locations = 0;
16732            for ranges in locations.values_mut() {
16733                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
16734                ranges.dedup();
16735                num_locations += ranges.len();
16736            }
16737
16738            if num_locations > 1 {
16739                let Some(workspace) = workspace else {
16740                    return Ok(Navigated::No);
16741                };
16742
16743                let tab_kind = match kind {
16744                    Some(GotoDefinitionKind::Implementation) => "Implementations",
16745                    Some(GotoDefinitionKind::Symbol) | None => "Definitions",
16746                    Some(GotoDefinitionKind::Declaration) => "Declarations",
16747                    Some(GotoDefinitionKind::Type) => "Types",
16748                };
16749                let title = editor
16750                    .update_in(cx, |_, _, cx| {
16751                        let target = locations
16752                            .iter()
16753                            .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
16754                            .map(|(buffer, location)| {
16755                                buffer
16756                                    .read(cx)
16757                                    .text_for_range(location.clone())
16758                                    .collect::<String>()
16759                            })
16760                            .filter(|text| !text.contains('\n'))
16761                            .unique()
16762                            .take(3)
16763                            .join(", ");
16764                        if target.is_empty() {
16765                            tab_kind.to_owned()
16766                        } else {
16767                            format!("{tab_kind} for {target}")
16768                        }
16769                    })
16770                    .context("buffer title")?;
16771
16772                let opened = workspace
16773                    .update_in(cx, |workspace, window, cx| {
16774                        Self::open_locations_in_multibuffer(
16775                            workspace,
16776                            locations,
16777                            title,
16778                            split,
16779                            MultibufferSelectionMode::First,
16780                            window,
16781                            cx,
16782                        )
16783                    })
16784                    .is_ok();
16785
16786                anyhow::Ok(Navigated::from_bool(opened))
16787            } else if num_locations == 0 {
16788                // If there is one url or file, open it directly
16789                match first_url_or_file {
16790                    Some(Either::Left(url)) => {
16791                        cx.update(|_, cx| cx.open_url(&url))?;
16792                        Ok(Navigated::Yes)
16793                    }
16794                    Some(Either::Right(path)) => {
16795                        let Some(workspace) = workspace else {
16796                            return Ok(Navigated::No);
16797                        };
16798
16799                        workspace
16800                            .update_in(cx, |workspace, window, cx| {
16801                                workspace.open_resolved_path(path, window, cx)
16802                            })?
16803                            .await?;
16804                        Ok(Navigated::Yes)
16805                    }
16806                    None => Ok(Navigated::No),
16807                }
16808            } else {
16809                let Some(workspace) = workspace else {
16810                    return Ok(Navigated::No);
16811                };
16812
16813                let (target_buffer, target_ranges) = locations.into_iter().next().unwrap();
16814                let target_range = target_ranges.first().unwrap().clone();
16815
16816                editor.update_in(cx, |editor, window, cx| {
16817                    let range = target_range.to_point(target_buffer.read(cx));
16818                    let range = editor.range_for_match(&range, false);
16819                    let range = collapse_multiline_range(range);
16820
16821                    if !split
16822                        && Some(&target_buffer) == editor.buffer.read(cx).as_singleton().as_ref()
16823                    {
16824                        editor.go_to_singleton_buffer_range(range, window, cx);
16825                    } else {
16826                        let pane = workspace.read(cx).active_pane().clone();
16827                        window.defer(cx, move |window, cx| {
16828                            let target_editor: Entity<Self> =
16829                                workspace.update(cx, |workspace, cx| {
16830                                    let pane = if split {
16831                                        workspace.adjacent_pane(window, cx)
16832                                    } else {
16833                                        workspace.active_pane().clone()
16834                                    };
16835
16836                                    workspace.open_project_item(
16837                                        pane,
16838                                        target_buffer.clone(),
16839                                        true,
16840                                        true,
16841                                        window,
16842                                        cx,
16843                                    )
16844                                });
16845                            target_editor.update(cx, |target_editor, cx| {
16846                                // When selecting a definition in a different buffer, disable the nav history
16847                                // to avoid creating a history entry at the previous cursor location.
16848                                pane.update(cx, |pane, _| pane.disable_history());
16849                                target_editor.go_to_singleton_buffer_range(range, window, cx);
16850                                pane.update(cx, |pane, _| pane.enable_history());
16851                            });
16852                        });
16853                    }
16854                    Navigated::Yes
16855                })
16856            }
16857        })
16858    }
16859
16860    fn compute_target_location(
16861        &self,
16862        lsp_location: lsp::Location,
16863        server_id: LanguageServerId,
16864        window: &mut Window,
16865        cx: &mut Context<Self>,
16866    ) -> Task<anyhow::Result<Option<Location>>> {
16867        let Some(project) = self.project.clone() else {
16868            return Task::ready(Ok(None));
16869        };
16870
16871        cx.spawn_in(window, async move |editor, cx| {
16872            let location_task = editor.update(cx, |_, cx| {
16873                project.update(cx, |project, cx| {
16874                    project.open_local_buffer_via_lsp(lsp_location.uri.clone(), server_id, cx)
16875                })
16876            })?;
16877            let location = Some({
16878                let target_buffer_handle = location_task.await.context("open local buffer")?;
16879                let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
16880                    let target_start = target_buffer
16881                        .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
16882                    let target_end = target_buffer
16883                        .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
16884                    target_buffer.anchor_after(target_start)
16885                        ..target_buffer.anchor_before(target_end)
16886                })?;
16887                Location {
16888                    buffer: target_buffer_handle,
16889                    range,
16890                }
16891            });
16892            Ok(location)
16893        })
16894    }
16895
16896    fn go_to_next_reference(
16897        &mut self,
16898        _: &GoToNextReference,
16899        window: &mut Window,
16900        cx: &mut Context<Self>,
16901    ) {
16902        let task = self.go_to_reference_before_or_after_position(Direction::Next, 1, window, cx);
16903        if let Some(task) = task {
16904            task.detach();
16905        };
16906    }
16907
16908    fn go_to_prev_reference(
16909        &mut self,
16910        _: &GoToPreviousReference,
16911        window: &mut Window,
16912        cx: &mut Context<Self>,
16913    ) {
16914        let task = self.go_to_reference_before_or_after_position(Direction::Prev, 1, window, cx);
16915        if let Some(task) = task {
16916            task.detach();
16917        };
16918    }
16919
16920    pub fn go_to_reference_before_or_after_position(
16921        &mut self,
16922        direction: Direction,
16923        count: usize,
16924        window: &mut Window,
16925        cx: &mut Context<Self>,
16926    ) -> Option<Task<Result<()>>> {
16927        let selection = self.selections.newest_anchor();
16928        let head = selection.head();
16929
16930        let multi_buffer = self.buffer.read(cx);
16931
16932        let (buffer, text_head) = multi_buffer.text_anchor_for_position(head, cx)?;
16933        let workspace = self.workspace()?;
16934        let project = workspace.read(cx).project().clone();
16935        let references =
16936            project.update(cx, |project, cx| project.references(&buffer, text_head, cx));
16937        Some(cx.spawn_in(window, async move |editor, cx| -> Result<()> {
16938            let Some(locations) = references.await? else {
16939                return Ok(());
16940            };
16941
16942            if locations.is_empty() {
16943                // totally normal - the cursor may be on something which is not
16944                // a symbol (e.g. a keyword)
16945                log::info!("no references found under cursor");
16946                return Ok(());
16947            }
16948
16949            let multi_buffer = editor.read_with(cx, |editor, _| editor.buffer().clone())?;
16950
16951            let multi_buffer_snapshot =
16952                multi_buffer.read_with(cx, |multi_buffer, cx| multi_buffer.snapshot(cx))?;
16953
16954            let (locations, current_location_index) =
16955                multi_buffer.update(cx, |multi_buffer, cx| {
16956                    let mut locations = locations
16957                        .into_iter()
16958                        .filter_map(|loc| {
16959                            let start = multi_buffer.buffer_anchor_to_anchor(
16960                                &loc.buffer,
16961                                loc.range.start,
16962                                cx,
16963                            )?;
16964                            let end = multi_buffer.buffer_anchor_to_anchor(
16965                                &loc.buffer,
16966                                loc.range.end,
16967                                cx,
16968                            )?;
16969                            Some(start..end)
16970                        })
16971                        .collect::<Vec<_>>();
16972
16973                    // There is an O(n) implementation, but given this list will be
16974                    // small (usually <100 items), the extra O(log(n)) factor isn't
16975                    // worth the (surprisingly large amount of) extra complexity.
16976                    locations
16977                        .sort_unstable_by(|l, r| l.start.cmp(&r.start, &multi_buffer_snapshot));
16978
16979                    let head_offset = head.to_offset(&multi_buffer_snapshot);
16980
16981                    let current_location_index = locations.iter().position(|loc| {
16982                        loc.start.to_offset(&multi_buffer_snapshot) <= head_offset
16983                            && loc.end.to_offset(&multi_buffer_snapshot) >= head_offset
16984                    });
16985
16986                    (locations, current_location_index)
16987                })?;
16988
16989            let Some(current_location_index) = current_location_index else {
16990                // This indicates something has gone wrong, because we already
16991                // handle the "no references" case above
16992                log::error!(
16993                    "failed to find current reference under cursor. Total references: {}",
16994                    locations.len()
16995                );
16996                return Ok(());
16997            };
16998
16999            let destination_location_index = match direction {
17000                Direction::Next => (current_location_index + count) % locations.len(),
17001                Direction::Prev => {
17002                    (current_location_index + locations.len() - count % locations.len())
17003                        % locations.len()
17004                }
17005            };
17006
17007            // TODO(cameron): is this needed?
17008            // the thinking is to avoid "jumping to the current location" (avoid
17009            // polluting "jumplist" in vim terms)
17010            if current_location_index == destination_location_index {
17011                return Ok(());
17012            }
17013
17014            let Range { start, end } = locations[destination_location_index];
17015
17016            editor.update_in(cx, |editor, window, cx| {
17017                let effects = SelectionEffects::default();
17018
17019                editor.unfold_ranges(&[start..end], false, false, cx);
17020                editor.change_selections(effects, window, cx, |s| {
17021                    s.select_ranges([start..start]);
17022                });
17023            })?;
17024
17025            Ok(())
17026        }))
17027    }
17028
17029    pub fn find_all_references(
17030        &mut self,
17031        _: &FindAllReferences,
17032        window: &mut Window,
17033        cx: &mut Context<Self>,
17034    ) -> Option<Task<Result<Navigated>>> {
17035        let selection = self.selections.newest::<usize>(&self.display_snapshot(cx));
17036        let multi_buffer = self.buffer.read(cx);
17037        let head = selection.head();
17038
17039        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
17040        let head_anchor = multi_buffer_snapshot.anchor_at(
17041            head,
17042            if head < selection.tail() {
17043                Bias::Right
17044            } else {
17045                Bias::Left
17046            },
17047        );
17048
17049        match self
17050            .find_all_references_task_sources
17051            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
17052        {
17053            Ok(_) => {
17054                log::info!(
17055                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
17056                );
17057                return None;
17058            }
17059            Err(i) => {
17060                self.find_all_references_task_sources.insert(i, head_anchor);
17061            }
17062        }
17063
17064        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
17065        let workspace = self.workspace()?;
17066        let project = workspace.read(cx).project().clone();
17067        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
17068        Some(cx.spawn_in(window, async move |editor, cx| {
17069            let _cleanup = cx.on_drop(&editor, move |editor, _| {
17070                if let Ok(i) = editor
17071                    .find_all_references_task_sources
17072                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
17073                {
17074                    editor.find_all_references_task_sources.remove(i);
17075                }
17076            });
17077
17078            let Some(locations) = references.await? else {
17079                return anyhow::Ok(Navigated::No);
17080            };
17081            let mut locations = cx.update(|_, cx| {
17082                locations
17083                    .into_iter()
17084                    .map(|location| {
17085                        let buffer = location.buffer.read(cx);
17086                        (location.buffer, location.range.to_point(buffer))
17087                    })
17088                    .into_group_map()
17089            })?;
17090            if locations.is_empty() {
17091                return anyhow::Ok(Navigated::No);
17092            }
17093            for ranges in locations.values_mut() {
17094                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
17095                ranges.dedup();
17096            }
17097
17098            workspace.update_in(cx, |workspace, window, cx| {
17099                let target = locations
17100                    .iter()
17101                    .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
17102                    .map(|(buffer, location)| {
17103                        buffer
17104                            .read(cx)
17105                            .text_for_range(location.clone())
17106                            .collect::<String>()
17107                    })
17108                    .filter(|text| !text.contains('\n'))
17109                    .unique()
17110                    .take(3)
17111                    .join(", ");
17112                let title = if target.is_empty() {
17113                    "References".to_owned()
17114                } else {
17115                    format!("References to {target}")
17116                };
17117                Self::open_locations_in_multibuffer(
17118                    workspace,
17119                    locations,
17120                    title,
17121                    false,
17122                    MultibufferSelectionMode::First,
17123                    window,
17124                    cx,
17125                );
17126                Navigated::Yes
17127            })
17128        }))
17129    }
17130
17131    /// Opens a multibuffer with the given project locations in it
17132    pub fn open_locations_in_multibuffer(
17133        workspace: &mut Workspace,
17134        locations: std::collections::HashMap<Entity<Buffer>, Vec<Range<Point>>>,
17135        title: String,
17136        split: bool,
17137        multibuffer_selection_mode: MultibufferSelectionMode,
17138        window: &mut Window,
17139        cx: &mut Context<Workspace>,
17140    ) {
17141        if locations.is_empty() {
17142            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
17143            return;
17144        }
17145
17146        let capability = workspace.project().read(cx).capability();
17147        let mut ranges = <Vec<Range<Anchor>>>::new();
17148
17149        // a key to find existing multibuffer editors with the same set of locations
17150        // to prevent us from opening more and more multibuffer tabs for searches and the like
17151        let mut key = (title.clone(), vec![]);
17152        let excerpt_buffer = cx.new(|cx| {
17153            let key = &mut key.1;
17154            let mut multibuffer = MultiBuffer::new(capability);
17155            for (buffer, mut ranges_for_buffer) in locations {
17156                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
17157                key.push((buffer.read(cx).remote_id(), ranges_for_buffer.clone()));
17158                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
17159                    PathKey::for_buffer(&buffer, cx),
17160                    buffer.clone(),
17161                    ranges_for_buffer,
17162                    multibuffer_context_lines(cx),
17163                    cx,
17164                );
17165                ranges.extend(new_ranges)
17166            }
17167
17168            multibuffer.with_title(title)
17169        });
17170        let existing = workspace.active_pane().update(cx, |pane, cx| {
17171            pane.items()
17172                .filter_map(|item| item.downcast::<Editor>())
17173                .find(|editor| {
17174                    editor
17175                        .read(cx)
17176                        .lookup_key
17177                        .as_ref()
17178                        .and_then(|it| {
17179                            it.downcast_ref::<(String, Vec<(BufferId, Vec<Range<Point>>)>)>()
17180                        })
17181                        .is_some_and(|it| *it == key)
17182                })
17183        });
17184        let editor = existing.unwrap_or_else(|| {
17185            cx.new(|cx| {
17186                let mut editor = Editor::for_multibuffer(
17187                    excerpt_buffer,
17188                    Some(workspace.project().clone()),
17189                    window,
17190                    cx,
17191                );
17192                editor.lookup_key = Some(Box::new(key));
17193                editor
17194            })
17195        });
17196        editor.update(cx, |editor, cx| match multibuffer_selection_mode {
17197            MultibufferSelectionMode::First => {
17198                if let Some(first_range) = ranges.first() {
17199                    editor.change_selections(
17200                        SelectionEffects::no_scroll(),
17201                        window,
17202                        cx,
17203                        |selections| {
17204                            selections.clear_disjoint();
17205                            selections.select_anchor_ranges(std::iter::once(first_range.clone()));
17206                        },
17207                    );
17208                }
17209                editor.highlight_background::<Self>(
17210                    &ranges,
17211                    |theme| theme.colors().editor_highlighted_line_background,
17212                    cx,
17213                );
17214            }
17215            MultibufferSelectionMode::All => {
17216                editor.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
17217                    selections.clear_disjoint();
17218                    selections.select_anchor_ranges(ranges);
17219                });
17220            }
17221        });
17222
17223        let item = Box::new(editor);
17224        let item_id = item.item_id();
17225
17226        if split {
17227            let pane = workspace.adjacent_pane(window, cx);
17228            workspace.add_item(pane, item, None, true, true, window, cx);
17229        } else if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
17230            let (preview_item_id, preview_item_idx) =
17231                workspace.active_pane().read_with(cx, |pane, _| {
17232                    (pane.preview_item_id(), pane.preview_item_idx())
17233                });
17234
17235            workspace.add_item_to_active_pane(item, preview_item_idx, true, window, cx);
17236
17237            if let Some(preview_item_id) = preview_item_id {
17238                workspace.active_pane().update(cx, |pane, cx| {
17239                    pane.remove_item(preview_item_id, false, false, window, cx);
17240                });
17241            }
17242        } else {
17243            workspace.add_item_to_active_pane(item, None, true, window, cx);
17244        }
17245        workspace.active_pane().update(cx, |pane, cx| {
17246            pane.set_preview_item_id(Some(item_id), cx);
17247        });
17248    }
17249
17250    pub fn rename(
17251        &mut self,
17252        _: &Rename,
17253        window: &mut Window,
17254        cx: &mut Context<Self>,
17255    ) -> Option<Task<Result<()>>> {
17256        use language::ToOffset as _;
17257
17258        let provider = self.semantics_provider.clone()?;
17259        let selection = self.selections.newest_anchor().clone();
17260        let (cursor_buffer, cursor_buffer_position) = self
17261            .buffer
17262            .read(cx)
17263            .text_anchor_for_position(selection.head(), cx)?;
17264        let (tail_buffer, cursor_buffer_position_end) = self
17265            .buffer
17266            .read(cx)
17267            .text_anchor_for_position(selection.tail(), cx)?;
17268        if tail_buffer != cursor_buffer {
17269            return None;
17270        }
17271
17272        let snapshot = cursor_buffer.read(cx).snapshot();
17273        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
17274        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
17275        let prepare_rename = provider
17276            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
17277            .unwrap_or_else(|| Task::ready(Ok(None)));
17278        drop(snapshot);
17279
17280        Some(cx.spawn_in(window, async move |this, cx| {
17281            let rename_range = if let Some(range) = prepare_rename.await? {
17282                Some(range)
17283            } else {
17284                this.update(cx, |this, cx| {
17285                    let buffer = this.buffer.read(cx).snapshot(cx);
17286                    let mut buffer_highlights = this
17287                        .document_highlights_for_position(selection.head(), &buffer)
17288                        .filter(|highlight| {
17289                            highlight.start.excerpt_id == selection.head().excerpt_id
17290                                && highlight.end.excerpt_id == selection.head().excerpt_id
17291                        });
17292                    buffer_highlights
17293                        .next()
17294                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
17295                })?
17296            };
17297            if let Some(rename_range) = rename_range {
17298                this.update_in(cx, |this, window, cx| {
17299                    let snapshot = cursor_buffer.read(cx).snapshot();
17300                    let rename_buffer_range = rename_range.to_offset(&snapshot);
17301                    let cursor_offset_in_rename_range =
17302                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
17303                    let cursor_offset_in_rename_range_end =
17304                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
17305
17306                    this.take_rename(false, window, cx);
17307                    let buffer = this.buffer.read(cx).read(cx);
17308                    let cursor_offset = selection.head().to_offset(&buffer);
17309                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
17310                    let rename_end = rename_start + rename_buffer_range.len();
17311                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
17312                    let mut old_highlight_id = None;
17313                    let old_name: Arc<str> = buffer
17314                        .chunks(rename_start..rename_end, true)
17315                        .map(|chunk| {
17316                            if old_highlight_id.is_none() {
17317                                old_highlight_id = chunk.syntax_highlight_id;
17318                            }
17319                            chunk.text
17320                        })
17321                        .collect::<String>()
17322                        .into();
17323
17324                    drop(buffer);
17325
17326                    // Position the selection in the rename editor so that it matches the current selection.
17327                    this.show_local_selections = false;
17328                    let rename_editor = cx.new(|cx| {
17329                        let mut editor = Editor::single_line(window, cx);
17330                        editor.buffer.update(cx, |buffer, cx| {
17331                            buffer.edit([(0..0, old_name.clone())], None, cx)
17332                        });
17333                        let rename_selection_range = match cursor_offset_in_rename_range
17334                            .cmp(&cursor_offset_in_rename_range_end)
17335                        {
17336                            Ordering::Equal => {
17337                                editor.select_all(&SelectAll, window, cx);
17338                                return editor;
17339                            }
17340                            Ordering::Less => {
17341                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
17342                            }
17343                            Ordering::Greater => {
17344                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
17345                            }
17346                        };
17347                        if rename_selection_range.end > old_name.len() {
17348                            editor.select_all(&SelectAll, window, cx);
17349                        } else {
17350                            editor.change_selections(Default::default(), window, cx, |s| {
17351                                s.select_ranges([rename_selection_range]);
17352                            });
17353                        }
17354                        editor
17355                    });
17356                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
17357                        if e == &EditorEvent::Focused {
17358                            cx.emit(EditorEvent::FocusedIn)
17359                        }
17360                    })
17361                    .detach();
17362
17363                    let write_highlights =
17364                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
17365                    let read_highlights =
17366                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
17367                    let ranges = write_highlights
17368                        .iter()
17369                        .flat_map(|(_, ranges)| ranges.iter())
17370                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
17371                        .cloned()
17372                        .collect();
17373
17374                    this.highlight_text::<Rename>(
17375                        ranges,
17376                        HighlightStyle {
17377                            fade_out: Some(0.6),
17378                            ..Default::default()
17379                        },
17380                        cx,
17381                    );
17382                    let rename_focus_handle = rename_editor.focus_handle(cx);
17383                    window.focus(&rename_focus_handle);
17384                    let block_id = this.insert_blocks(
17385                        [BlockProperties {
17386                            style: BlockStyle::Flex,
17387                            placement: BlockPlacement::Below(range.start),
17388                            height: Some(1),
17389                            render: Arc::new({
17390                                let rename_editor = rename_editor.clone();
17391                                move |cx: &mut BlockContext| {
17392                                    let mut text_style = cx.editor_style.text.clone();
17393                                    if let Some(highlight_style) = old_highlight_id
17394                                        .and_then(|h| h.style(&cx.editor_style.syntax))
17395                                    {
17396                                        text_style = text_style.highlight(highlight_style);
17397                                    }
17398                                    div()
17399                                        .block_mouse_except_scroll()
17400                                        .pl(cx.anchor_x)
17401                                        .child(EditorElement::new(
17402                                            &rename_editor,
17403                                            EditorStyle {
17404                                                background: cx.theme().system().transparent,
17405                                                local_player: cx.editor_style.local_player,
17406                                                text: text_style,
17407                                                scrollbar_width: cx.editor_style.scrollbar_width,
17408                                                syntax: cx.editor_style.syntax.clone(),
17409                                                status: cx.editor_style.status.clone(),
17410                                                inlay_hints_style: HighlightStyle {
17411                                                    font_weight: Some(FontWeight::BOLD),
17412                                                    ..make_inlay_hints_style(cx.app)
17413                                                },
17414                                                edit_prediction_styles: make_suggestion_styles(
17415                                                    cx.app,
17416                                                ),
17417                                                ..EditorStyle::default()
17418                                            },
17419                                        ))
17420                                        .into_any_element()
17421                                }
17422                            }),
17423                            priority: 0,
17424                        }],
17425                        Some(Autoscroll::fit()),
17426                        cx,
17427                    )[0];
17428                    this.pending_rename = Some(RenameState {
17429                        range,
17430                        old_name,
17431                        editor: rename_editor,
17432                        block_id,
17433                    });
17434                })?;
17435            }
17436
17437            Ok(())
17438        }))
17439    }
17440
17441    pub fn confirm_rename(
17442        &mut self,
17443        _: &ConfirmRename,
17444        window: &mut Window,
17445        cx: &mut Context<Self>,
17446    ) -> Option<Task<Result<()>>> {
17447        let rename = self.take_rename(false, window, cx)?;
17448        let workspace = self.workspace()?.downgrade();
17449        let (buffer, start) = self
17450            .buffer
17451            .read(cx)
17452            .text_anchor_for_position(rename.range.start, cx)?;
17453        let (end_buffer, _) = self
17454            .buffer
17455            .read(cx)
17456            .text_anchor_for_position(rename.range.end, cx)?;
17457        if buffer != end_buffer {
17458            return None;
17459        }
17460
17461        let old_name = rename.old_name;
17462        let new_name = rename.editor.read(cx).text(cx);
17463
17464        let rename = self.semantics_provider.as_ref()?.perform_rename(
17465            &buffer,
17466            start,
17467            new_name.clone(),
17468            cx,
17469        )?;
17470
17471        Some(cx.spawn_in(window, async move |editor, cx| {
17472            let project_transaction = rename.await?;
17473            Self::open_project_transaction(
17474                &editor,
17475                workspace,
17476                project_transaction,
17477                format!("Rename: {}{}", old_name, new_name),
17478                cx,
17479            )
17480            .await?;
17481
17482            editor.update(cx, |editor, cx| {
17483                editor.refresh_document_highlights(cx);
17484            })?;
17485            Ok(())
17486        }))
17487    }
17488
17489    fn take_rename(
17490        &mut self,
17491        moving_cursor: bool,
17492        window: &mut Window,
17493        cx: &mut Context<Self>,
17494    ) -> Option<RenameState> {
17495        let rename = self.pending_rename.take()?;
17496        if rename.editor.focus_handle(cx).is_focused(window) {
17497            window.focus(&self.focus_handle);
17498        }
17499
17500        self.remove_blocks(
17501            [rename.block_id].into_iter().collect(),
17502            Some(Autoscroll::fit()),
17503            cx,
17504        );
17505        self.clear_highlights::<Rename>(cx);
17506        self.show_local_selections = true;
17507
17508        if moving_cursor {
17509            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
17510                editor
17511                    .selections
17512                    .newest::<usize>(&editor.display_snapshot(cx))
17513                    .head()
17514            });
17515
17516            // Update the selection to match the position of the selection inside
17517            // the rename editor.
17518            let snapshot = self.buffer.read(cx).read(cx);
17519            let rename_range = rename.range.to_offset(&snapshot);
17520            let cursor_in_editor = snapshot
17521                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
17522                .min(rename_range.end);
17523            drop(snapshot);
17524
17525            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17526                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
17527            });
17528        } else {
17529            self.refresh_document_highlights(cx);
17530        }
17531
17532        Some(rename)
17533    }
17534
17535    pub fn pending_rename(&self) -> Option<&RenameState> {
17536        self.pending_rename.as_ref()
17537    }
17538
17539    fn format(
17540        &mut self,
17541        _: &Format,
17542        window: &mut Window,
17543        cx: &mut Context<Self>,
17544    ) -> Option<Task<Result<()>>> {
17545        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17546
17547        let project = match &self.project {
17548            Some(project) => project.clone(),
17549            None => return None,
17550        };
17551
17552        Some(self.perform_format(
17553            project,
17554            FormatTrigger::Manual,
17555            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
17556            window,
17557            cx,
17558        ))
17559    }
17560
17561    fn format_selections(
17562        &mut self,
17563        _: &FormatSelections,
17564        window: &mut Window,
17565        cx: &mut Context<Self>,
17566    ) -> Option<Task<Result<()>>> {
17567        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17568
17569        let project = match &self.project {
17570            Some(project) => project.clone(),
17571            None => return None,
17572        };
17573
17574        let ranges = self
17575            .selections
17576            .all_adjusted(&self.display_snapshot(cx))
17577            .into_iter()
17578            .map(|selection| selection.range())
17579            .collect_vec();
17580
17581        Some(self.perform_format(
17582            project,
17583            FormatTrigger::Manual,
17584            FormatTarget::Ranges(ranges),
17585            window,
17586            cx,
17587        ))
17588    }
17589
17590    fn perform_format(
17591        &mut self,
17592        project: Entity<Project>,
17593        trigger: FormatTrigger,
17594        target: FormatTarget,
17595        window: &mut Window,
17596        cx: &mut Context<Self>,
17597    ) -> Task<Result<()>> {
17598        let buffer = self.buffer.clone();
17599        let (buffers, target) = match target {
17600            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
17601            FormatTarget::Ranges(selection_ranges) => {
17602                let multi_buffer = buffer.read(cx);
17603                let snapshot = multi_buffer.read(cx);
17604                let mut buffers = HashSet::default();
17605                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
17606                    BTreeMap::new();
17607                for selection_range in selection_ranges {
17608                    for (buffer, buffer_range, _) in
17609                        snapshot.range_to_buffer_ranges(selection_range)
17610                    {
17611                        let buffer_id = buffer.remote_id();
17612                        let start = buffer.anchor_before(buffer_range.start);
17613                        let end = buffer.anchor_after(buffer_range.end);
17614                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
17615                        buffer_id_to_ranges
17616                            .entry(buffer_id)
17617                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
17618                            .or_insert_with(|| vec![start..end]);
17619                    }
17620                }
17621                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
17622            }
17623        };
17624
17625        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
17626        let selections_prev = transaction_id_prev
17627            .and_then(|transaction_id_prev| {
17628                // default to selections as they were after the last edit, if we have them,
17629                // instead of how they are now.
17630                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
17631                // will take you back to where you made the last edit, instead of staying where you scrolled
17632                self.selection_history
17633                    .transaction(transaction_id_prev)
17634                    .map(|t| t.0.clone())
17635            })
17636            .unwrap_or_else(|| self.selections.disjoint_anchors_arc());
17637
17638        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
17639        let format = project.update(cx, |project, cx| {
17640            project.format(buffers, target, true, trigger, cx)
17641        });
17642
17643        cx.spawn_in(window, async move |editor, cx| {
17644            let transaction = futures::select_biased! {
17645                transaction = format.log_err().fuse() => transaction,
17646                () = timeout => {
17647                    log::warn!("timed out waiting for formatting");
17648                    None
17649                }
17650            };
17651
17652            buffer
17653                .update(cx, |buffer, cx| {
17654                    if let Some(transaction) = transaction
17655                        && !buffer.is_singleton()
17656                    {
17657                        buffer.push_transaction(&transaction.0, cx);
17658                    }
17659                    cx.notify();
17660                })
17661                .ok();
17662
17663            if let Some(transaction_id_now) =
17664                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
17665            {
17666                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
17667                if has_new_transaction {
17668                    _ = editor.update(cx, |editor, _| {
17669                        editor
17670                            .selection_history
17671                            .insert_transaction(transaction_id_now, selections_prev);
17672                    });
17673                }
17674            }
17675
17676            Ok(())
17677        })
17678    }
17679
17680    fn organize_imports(
17681        &mut self,
17682        _: &OrganizeImports,
17683        window: &mut Window,
17684        cx: &mut Context<Self>,
17685    ) -> Option<Task<Result<()>>> {
17686        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17687        let project = match &self.project {
17688            Some(project) => project.clone(),
17689            None => return None,
17690        };
17691        Some(self.perform_code_action_kind(
17692            project,
17693            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
17694            window,
17695            cx,
17696        ))
17697    }
17698
17699    fn perform_code_action_kind(
17700        &mut self,
17701        project: Entity<Project>,
17702        kind: CodeActionKind,
17703        window: &mut Window,
17704        cx: &mut Context<Self>,
17705    ) -> Task<Result<()>> {
17706        let buffer = self.buffer.clone();
17707        let buffers = buffer.read(cx).all_buffers();
17708        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
17709        let apply_action = project.update(cx, |project, cx| {
17710            project.apply_code_action_kind(buffers, kind, true, cx)
17711        });
17712        cx.spawn_in(window, async move |_, cx| {
17713            let transaction = futures::select_biased! {
17714                () = timeout => {
17715                    log::warn!("timed out waiting for executing code action");
17716                    None
17717                }
17718                transaction = apply_action.log_err().fuse() => transaction,
17719            };
17720            buffer
17721                .update(cx, |buffer, cx| {
17722                    // check if we need this
17723                    if let Some(transaction) = transaction
17724                        && !buffer.is_singleton()
17725                    {
17726                        buffer.push_transaction(&transaction.0, cx);
17727                    }
17728                    cx.notify();
17729                })
17730                .ok();
17731            Ok(())
17732        })
17733    }
17734
17735    pub fn restart_language_server(
17736        &mut self,
17737        _: &RestartLanguageServer,
17738        _: &mut Window,
17739        cx: &mut Context<Self>,
17740    ) {
17741        if let Some(project) = self.project.clone() {
17742            self.buffer.update(cx, |multi_buffer, cx| {
17743                project.update(cx, |project, cx| {
17744                    project.restart_language_servers_for_buffers(
17745                        multi_buffer.all_buffers().into_iter().collect(),
17746                        HashSet::default(),
17747                        cx,
17748                    );
17749                });
17750            })
17751        }
17752    }
17753
17754    pub fn stop_language_server(
17755        &mut self,
17756        _: &StopLanguageServer,
17757        _: &mut Window,
17758        cx: &mut Context<Self>,
17759    ) {
17760        if let Some(project) = self.project.clone() {
17761            self.buffer.update(cx, |multi_buffer, cx| {
17762                project.update(cx, |project, cx| {
17763                    project.stop_language_servers_for_buffers(
17764                        multi_buffer.all_buffers().into_iter().collect(),
17765                        HashSet::default(),
17766                        cx,
17767                    );
17768                });
17769            });
17770            self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
17771        }
17772    }
17773
17774    fn cancel_language_server_work(
17775        workspace: &mut Workspace,
17776        _: &actions::CancelLanguageServerWork,
17777        _: &mut Window,
17778        cx: &mut Context<Workspace>,
17779    ) {
17780        let project = workspace.project();
17781        let buffers = workspace
17782            .active_item(cx)
17783            .and_then(|item| item.act_as::<Editor>(cx))
17784            .map_or(HashSet::default(), |editor| {
17785                editor.read(cx).buffer.read(cx).all_buffers()
17786            });
17787        project.update(cx, |project, cx| {
17788            project.cancel_language_server_work_for_buffers(buffers, cx);
17789        });
17790    }
17791
17792    fn show_character_palette(
17793        &mut self,
17794        _: &ShowCharacterPalette,
17795        window: &mut Window,
17796        _: &mut Context<Self>,
17797    ) {
17798        window.show_character_palette();
17799    }
17800
17801    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
17802        if !self.diagnostics_enabled() {
17803            return;
17804        }
17805
17806        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
17807            let buffer = self.buffer.read(cx).snapshot(cx);
17808            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
17809            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
17810            let is_valid = buffer
17811                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
17812                .any(|entry| {
17813                    entry.diagnostic.is_primary
17814                        && !entry.range.is_empty()
17815                        && entry.range.start == primary_range_start
17816                        && entry.diagnostic.message == active_diagnostics.active_message
17817                });
17818
17819            if !is_valid {
17820                self.dismiss_diagnostics(cx);
17821            }
17822        }
17823    }
17824
17825    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
17826        match &self.active_diagnostics {
17827            ActiveDiagnostic::Group(group) => Some(group),
17828            _ => None,
17829        }
17830    }
17831
17832    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
17833        if !self.diagnostics_enabled() {
17834            return;
17835        }
17836        self.dismiss_diagnostics(cx);
17837        self.active_diagnostics = ActiveDiagnostic::All;
17838    }
17839
17840    fn activate_diagnostics(
17841        &mut self,
17842        buffer_id: BufferId,
17843        diagnostic: DiagnosticEntryRef<'_, usize>,
17844        window: &mut Window,
17845        cx: &mut Context<Self>,
17846    ) {
17847        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
17848            return;
17849        }
17850        self.dismiss_diagnostics(cx);
17851        let snapshot = self.snapshot(window, cx);
17852        let buffer = self.buffer.read(cx).snapshot(cx);
17853        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
17854            return;
17855        };
17856
17857        let diagnostic_group = buffer
17858            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
17859            .collect::<Vec<_>>();
17860
17861        let blocks =
17862            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
17863
17864        let blocks = self.display_map.update(cx, |display_map, cx| {
17865            display_map.insert_blocks(blocks, cx).into_iter().collect()
17866        });
17867        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
17868            active_range: buffer.anchor_before(diagnostic.range.start)
17869                ..buffer.anchor_after(diagnostic.range.end),
17870            active_message: diagnostic.diagnostic.message.clone(),
17871            group_id: diagnostic.diagnostic.group_id,
17872            blocks,
17873        });
17874        cx.notify();
17875    }
17876
17877    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
17878        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
17879            return;
17880        };
17881
17882        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
17883        if let ActiveDiagnostic::Group(group) = prev {
17884            self.display_map.update(cx, |display_map, cx| {
17885                display_map.remove_blocks(group.blocks, cx);
17886            });
17887            cx.notify();
17888        }
17889    }
17890
17891    /// Disable inline diagnostics rendering for this editor.
17892    pub fn disable_inline_diagnostics(&mut self) {
17893        self.inline_diagnostics_enabled = false;
17894        self.inline_diagnostics_update = Task::ready(());
17895        self.inline_diagnostics.clear();
17896    }
17897
17898    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
17899        self.diagnostics_enabled = false;
17900        self.dismiss_diagnostics(cx);
17901        self.inline_diagnostics_update = Task::ready(());
17902        self.inline_diagnostics.clear();
17903    }
17904
17905    pub fn disable_word_completions(&mut self) {
17906        self.word_completions_enabled = false;
17907    }
17908
17909    pub fn diagnostics_enabled(&self) -> bool {
17910        self.diagnostics_enabled && self.mode.is_full()
17911    }
17912
17913    pub fn inline_diagnostics_enabled(&self) -> bool {
17914        self.inline_diagnostics_enabled && self.diagnostics_enabled()
17915    }
17916
17917    pub fn show_inline_diagnostics(&self) -> bool {
17918        self.show_inline_diagnostics
17919    }
17920
17921    pub fn toggle_inline_diagnostics(
17922        &mut self,
17923        _: &ToggleInlineDiagnostics,
17924        window: &mut Window,
17925        cx: &mut Context<Editor>,
17926    ) {
17927        self.show_inline_diagnostics = !self.show_inline_diagnostics;
17928        self.refresh_inline_diagnostics(false, window, cx);
17929    }
17930
17931    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
17932        self.diagnostics_max_severity = severity;
17933        self.display_map.update(cx, |display_map, _| {
17934            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
17935        });
17936    }
17937
17938    pub fn toggle_diagnostics(
17939        &mut self,
17940        _: &ToggleDiagnostics,
17941        window: &mut Window,
17942        cx: &mut Context<Editor>,
17943    ) {
17944        if !self.diagnostics_enabled() {
17945            return;
17946        }
17947
17948        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
17949            EditorSettings::get_global(cx)
17950                .diagnostics_max_severity
17951                .filter(|severity| severity != &DiagnosticSeverity::Off)
17952                .unwrap_or(DiagnosticSeverity::Hint)
17953        } else {
17954            DiagnosticSeverity::Off
17955        };
17956        self.set_max_diagnostics_severity(new_severity, cx);
17957        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
17958            self.active_diagnostics = ActiveDiagnostic::None;
17959            self.inline_diagnostics_update = Task::ready(());
17960            self.inline_diagnostics.clear();
17961        } else {
17962            self.refresh_inline_diagnostics(false, window, cx);
17963        }
17964
17965        cx.notify();
17966    }
17967
17968    pub fn toggle_minimap(
17969        &mut self,
17970        _: &ToggleMinimap,
17971        window: &mut Window,
17972        cx: &mut Context<Editor>,
17973    ) {
17974        if self.supports_minimap(cx) {
17975            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
17976        }
17977    }
17978
17979    fn refresh_inline_diagnostics(
17980        &mut self,
17981        debounce: bool,
17982        window: &mut Window,
17983        cx: &mut Context<Self>,
17984    ) {
17985        let max_severity = ProjectSettings::get_global(cx)
17986            .diagnostics
17987            .inline
17988            .max_severity
17989            .unwrap_or(self.diagnostics_max_severity);
17990
17991        if !self.inline_diagnostics_enabled()
17992            || !self.diagnostics_enabled()
17993            || !self.show_inline_diagnostics
17994            || max_severity == DiagnosticSeverity::Off
17995        {
17996            self.inline_diagnostics_update = Task::ready(());
17997            self.inline_diagnostics.clear();
17998            return;
17999        }
18000
18001        let debounce_ms = ProjectSettings::get_global(cx)
18002            .diagnostics
18003            .inline
18004            .update_debounce_ms;
18005        let debounce = if debounce && debounce_ms > 0 {
18006            Some(Duration::from_millis(debounce_ms))
18007        } else {
18008            None
18009        };
18010        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
18011            if let Some(debounce) = debounce {
18012                cx.background_executor().timer(debounce).await;
18013            }
18014            let Some(snapshot) = editor.upgrade().and_then(|editor| {
18015                editor
18016                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
18017                    .ok()
18018            }) else {
18019                return;
18020            };
18021
18022            let new_inline_diagnostics = cx
18023                .background_spawn(async move {
18024                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
18025                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
18026                        let message = diagnostic_entry
18027                            .diagnostic
18028                            .message
18029                            .split_once('\n')
18030                            .map(|(line, _)| line)
18031                            .map(SharedString::new)
18032                            .unwrap_or_else(|| {
18033                                SharedString::new(&*diagnostic_entry.diagnostic.message)
18034                            });
18035                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
18036                        let (Ok(i) | Err(i)) = inline_diagnostics
18037                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
18038                        inline_diagnostics.insert(
18039                            i,
18040                            (
18041                                start_anchor,
18042                                InlineDiagnostic {
18043                                    message,
18044                                    group_id: diagnostic_entry.diagnostic.group_id,
18045                                    start: diagnostic_entry.range.start.to_point(&snapshot),
18046                                    is_primary: diagnostic_entry.diagnostic.is_primary,
18047                                    severity: diagnostic_entry.diagnostic.severity,
18048                                },
18049                            ),
18050                        );
18051                    }
18052                    inline_diagnostics
18053                })
18054                .await;
18055
18056            editor
18057                .update(cx, |editor, cx| {
18058                    editor.inline_diagnostics = new_inline_diagnostics;
18059                    cx.notify();
18060                })
18061                .ok();
18062        });
18063    }
18064
18065    fn pull_diagnostics(
18066        &mut self,
18067        buffer_id: Option<BufferId>,
18068        window: &Window,
18069        cx: &mut Context<Self>,
18070    ) -> Option<()> {
18071        if self.ignore_lsp_data() || !self.diagnostics_enabled() {
18072            return None;
18073        }
18074        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
18075            .diagnostics
18076            .lsp_pull_diagnostics;
18077        if !pull_diagnostics_settings.enabled {
18078            return None;
18079        }
18080        let project = self.project()?.downgrade();
18081        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
18082        let mut buffers = self.buffer.read(cx).all_buffers();
18083        buffers.retain(|buffer| {
18084            let buffer_id_to_retain = buffer.read(cx).remote_id();
18085            buffer_id.is_none_or(|buffer_id| buffer_id == buffer_id_to_retain)
18086                && self.registered_buffers.contains_key(&buffer_id_to_retain)
18087        });
18088        if buffers.is_empty() {
18089            self.pull_diagnostics_task = Task::ready(());
18090            return None;
18091        }
18092
18093        self.pull_diagnostics_task = cx.spawn_in(window, async move |editor, cx| {
18094            cx.background_executor().timer(debounce).await;
18095
18096            let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
18097                buffers
18098                    .into_iter()
18099                    .filter_map(|buffer| {
18100                        project
18101                            .update(cx, |project, cx| {
18102                                project.lsp_store().update(cx, |lsp_store, cx| {
18103                                    lsp_store.pull_diagnostics_for_buffer(buffer, cx)
18104                                })
18105                            })
18106                            .ok()
18107                    })
18108                    .collect::<FuturesUnordered<_>>()
18109            }) else {
18110                return;
18111            };
18112
18113            while let Some(pull_task) = pull_diagnostics_tasks.next().await {
18114                match pull_task {
18115                    Ok(()) => {
18116                        if editor
18117                            .update_in(cx, |editor, window, cx| {
18118                                editor.update_diagnostics_state(window, cx);
18119                            })
18120                            .is_err()
18121                        {
18122                            return;
18123                        }
18124                    }
18125                    Err(e) => log::error!("Failed to update project diagnostics: {e:#}"),
18126                }
18127            }
18128        });
18129
18130        Some(())
18131    }
18132
18133    pub fn set_selections_from_remote(
18134        &mut self,
18135        selections: Vec<Selection<Anchor>>,
18136        pending_selection: Option<Selection<Anchor>>,
18137        window: &mut Window,
18138        cx: &mut Context<Self>,
18139    ) {
18140        let old_cursor_position = self.selections.newest_anchor().head();
18141        self.selections
18142            .change_with(&self.display_snapshot(cx), |s| {
18143                s.select_anchors(selections);
18144                if let Some(pending_selection) = pending_selection {
18145                    s.set_pending(pending_selection, SelectMode::Character);
18146                } else {
18147                    s.clear_pending();
18148                }
18149            });
18150        self.selections_did_change(
18151            false,
18152            &old_cursor_position,
18153            SelectionEffects::default(),
18154            window,
18155            cx,
18156        );
18157    }
18158
18159    pub fn transact(
18160        &mut self,
18161        window: &mut Window,
18162        cx: &mut Context<Self>,
18163        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
18164    ) -> Option<TransactionId> {
18165        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
18166            this.start_transaction_at(Instant::now(), window, cx);
18167            update(this, window, cx);
18168            this.end_transaction_at(Instant::now(), cx)
18169        })
18170    }
18171
18172    pub fn start_transaction_at(
18173        &mut self,
18174        now: Instant,
18175        window: &mut Window,
18176        cx: &mut Context<Self>,
18177    ) -> Option<TransactionId> {
18178        self.end_selection(window, cx);
18179        if let Some(tx_id) = self
18180            .buffer
18181            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
18182        {
18183            self.selection_history
18184                .insert_transaction(tx_id, self.selections.disjoint_anchors_arc());
18185            cx.emit(EditorEvent::TransactionBegun {
18186                transaction_id: tx_id,
18187            });
18188            Some(tx_id)
18189        } else {
18190            None
18191        }
18192    }
18193
18194    pub fn end_transaction_at(
18195        &mut self,
18196        now: Instant,
18197        cx: &mut Context<Self>,
18198    ) -> Option<TransactionId> {
18199        if let Some(transaction_id) = self
18200            .buffer
18201            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
18202        {
18203            if let Some((_, end_selections)) =
18204                self.selection_history.transaction_mut(transaction_id)
18205            {
18206                *end_selections = Some(self.selections.disjoint_anchors_arc());
18207            } else {
18208                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
18209            }
18210
18211            cx.emit(EditorEvent::Edited { transaction_id });
18212            Some(transaction_id)
18213        } else {
18214            None
18215        }
18216    }
18217
18218    pub fn modify_transaction_selection_history(
18219        &mut self,
18220        transaction_id: TransactionId,
18221        modify: impl FnOnce(&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)),
18222    ) -> bool {
18223        self.selection_history
18224            .transaction_mut(transaction_id)
18225            .map(modify)
18226            .is_some()
18227    }
18228
18229    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
18230        if self.selection_mark_mode {
18231            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
18232                s.move_with(|_, sel| {
18233                    sel.collapse_to(sel.head(), SelectionGoal::None);
18234                });
18235            })
18236        }
18237        self.selection_mark_mode = true;
18238        cx.notify();
18239    }
18240
18241    pub fn swap_selection_ends(
18242        &mut self,
18243        _: &actions::SwapSelectionEnds,
18244        window: &mut Window,
18245        cx: &mut Context<Self>,
18246    ) {
18247        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
18248            s.move_with(|_, sel| {
18249                if sel.start != sel.end {
18250                    sel.reversed = !sel.reversed
18251                }
18252            });
18253        });
18254        self.request_autoscroll(Autoscroll::newest(), cx);
18255        cx.notify();
18256    }
18257
18258    pub fn toggle_focus(
18259        workspace: &mut Workspace,
18260        _: &actions::ToggleFocus,
18261        window: &mut Window,
18262        cx: &mut Context<Workspace>,
18263    ) {
18264        let Some(item) = workspace.recent_active_item_by_type::<Self>(cx) else {
18265            return;
18266        };
18267        workspace.activate_item(&item, true, true, window, cx);
18268    }
18269
18270    pub fn toggle_fold(
18271        &mut self,
18272        _: &actions::ToggleFold,
18273        window: &mut Window,
18274        cx: &mut Context<Self>,
18275    ) {
18276        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18277            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18278            let selection = self.selections.newest::<Point>(&display_map);
18279
18280            let range = if selection.is_empty() {
18281                let point = selection.head().to_display_point(&display_map);
18282                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
18283                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
18284                    .to_point(&display_map);
18285                start..end
18286            } else {
18287                selection.range()
18288            };
18289            if display_map.folds_in_range(range).next().is_some() {
18290                self.unfold_lines(&Default::default(), window, cx)
18291            } else {
18292                self.fold(&Default::default(), window, cx)
18293            }
18294        } else {
18295            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18296            let buffer_ids: HashSet<_> = self
18297                .selections
18298                .disjoint_anchor_ranges()
18299                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18300                .collect();
18301
18302            let should_unfold = buffer_ids
18303                .iter()
18304                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
18305
18306            for buffer_id in buffer_ids {
18307                if should_unfold {
18308                    self.unfold_buffer(buffer_id, cx);
18309                } else {
18310                    self.fold_buffer(buffer_id, cx);
18311                }
18312            }
18313        }
18314    }
18315
18316    pub fn toggle_fold_recursive(
18317        &mut self,
18318        _: &actions::ToggleFoldRecursive,
18319        window: &mut Window,
18320        cx: &mut Context<Self>,
18321    ) {
18322        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
18323
18324        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18325        let range = if selection.is_empty() {
18326            let point = selection.head().to_display_point(&display_map);
18327            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
18328            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
18329                .to_point(&display_map);
18330            start..end
18331        } else {
18332            selection.range()
18333        };
18334        if display_map.folds_in_range(range).next().is_some() {
18335            self.unfold_recursive(&Default::default(), window, cx)
18336        } else {
18337            self.fold_recursive(&Default::default(), window, cx)
18338        }
18339    }
18340
18341    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
18342        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18343            let mut to_fold = Vec::new();
18344            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18345            let selections = self.selections.all_adjusted(&display_map);
18346
18347            for selection in selections {
18348                let range = selection.range().sorted();
18349                let buffer_start_row = range.start.row;
18350
18351                if range.start.row != range.end.row {
18352                    let mut found = false;
18353                    let mut row = range.start.row;
18354                    while row <= range.end.row {
18355                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
18356                        {
18357                            found = true;
18358                            row = crease.range().end.row + 1;
18359                            to_fold.push(crease);
18360                        } else {
18361                            row += 1
18362                        }
18363                    }
18364                    if found {
18365                        continue;
18366                    }
18367                }
18368
18369                for row in (0..=range.start.row).rev() {
18370                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
18371                        && crease.range().end.row >= buffer_start_row
18372                    {
18373                        to_fold.push(crease);
18374                        if row <= range.start.row {
18375                            break;
18376                        }
18377                    }
18378                }
18379            }
18380
18381            self.fold_creases(to_fold, true, window, cx);
18382        } else {
18383            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18384            let buffer_ids = self
18385                .selections
18386                .disjoint_anchor_ranges()
18387                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18388                .collect::<HashSet<_>>();
18389            for buffer_id in buffer_ids {
18390                self.fold_buffer(buffer_id, cx);
18391            }
18392        }
18393    }
18394
18395    pub fn toggle_fold_all(
18396        &mut self,
18397        _: &actions::ToggleFoldAll,
18398        window: &mut Window,
18399        cx: &mut Context<Self>,
18400    ) {
18401        if self.buffer.read(cx).is_singleton() {
18402            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18403            let has_folds = display_map
18404                .folds_in_range(0..display_map.buffer_snapshot().len())
18405                .next()
18406                .is_some();
18407
18408            if has_folds {
18409                self.unfold_all(&actions::UnfoldAll, window, cx);
18410            } else {
18411                self.fold_all(&actions::FoldAll, window, cx);
18412            }
18413        } else {
18414            let buffer_ids = self.buffer.read(cx).excerpt_buffer_ids();
18415            let should_unfold = buffer_ids
18416                .iter()
18417                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
18418
18419            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
18420                editor
18421                    .update_in(cx, |editor, _, cx| {
18422                        for buffer_id in buffer_ids {
18423                            if should_unfold {
18424                                editor.unfold_buffer(buffer_id, cx);
18425                            } else {
18426                                editor.fold_buffer(buffer_id, cx);
18427                            }
18428                        }
18429                    })
18430                    .ok();
18431            });
18432        }
18433    }
18434
18435    fn fold_at_level(
18436        &mut self,
18437        fold_at: &FoldAtLevel,
18438        window: &mut Window,
18439        cx: &mut Context<Self>,
18440    ) {
18441        if !self.buffer.read(cx).is_singleton() {
18442            return;
18443        }
18444
18445        let fold_at_level = fold_at.0;
18446        let snapshot = self.buffer.read(cx).snapshot(cx);
18447        let mut to_fold = Vec::new();
18448        let mut stack = vec![(0, snapshot.max_row().0, 1)];
18449
18450        let row_ranges_to_keep: Vec<Range<u32>> = self
18451            .selections
18452            .all::<Point>(&self.display_snapshot(cx))
18453            .into_iter()
18454            .map(|sel| sel.start.row..sel.end.row)
18455            .collect();
18456
18457        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
18458            while start_row < end_row {
18459                match self
18460                    .snapshot(window, cx)
18461                    .crease_for_buffer_row(MultiBufferRow(start_row))
18462                {
18463                    Some(crease) => {
18464                        let nested_start_row = crease.range().start.row + 1;
18465                        let nested_end_row = crease.range().end.row;
18466
18467                        if current_level < fold_at_level {
18468                            stack.push((nested_start_row, nested_end_row, current_level + 1));
18469                        } else if current_level == fold_at_level {
18470                            // Fold iff there is no selection completely contained within the fold region
18471                            if !row_ranges_to_keep.iter().any(|selection| {
18472                                selection.end >= nested_start_row
18473                                    && selection.start <= nested_end_row
18474                            }) {
18475                                to_fold.push(crease);
18476                            }
18477                        }
18478
18479                        start_row = nested_end_row + 1;
18480                    }
18481                    None => start_row += 1,
18482                }
18483            }
18484        }
18485
18486        self.fold_creases(to_fold, true, window, cx);
18487    }
18488
18489    pub fn fold_at_level_1(
18490        &mut self,
18491        _: &actions::FoldAtLevel1,
18492        window: &mut Window,
18493        cx: &mut Context<Self>,
18494    ) {
18495        self.fold_at_level(&actions::FoldAtLevel(1), window, cx);
18496    }
18497
18498    pub fn fold_at_level_2(
18499        &mut self,
18500        _: &actions::FoldAtLevel2,
18501        window: &mut Window,
18502        cx: &mut Context<Self>,
18503    ) {
18504        self.fold_at_level(&actions::FoldAtLevel(2), window, cx);
18505    }
18506
18507    pub fn fold_at_level_3(
18508        &mut self,
18509        _: &actions::FoldAtLevel3,
18510        window: &mut Window,
18511        cx: &mut Context<Self>,
18512    ) {
18513        self.fold_at_level(&actions::FoldAtLevel(3), window, cx);
18514    }
18515
18516    pub fn fold_at_level_4(
18517        &mut self,
18518        _: &actions::FoldAtLevel4,
18519        window: &mut Window,
18520        cx: &mut Context<Self>,
18521    ) {
18522        self.fold_at_level(&actions::FoldAtLevel(4), window, cx);
18523    }
18524
18525    pub fn fold_at_level_5(
18526        &mut self,
18527        _: &actions::FoldAtLevel5,
18528        window: &mut Window,
18529        cx: &mut Context<Self>,
18530    ) {
18531        self.fold_at_level(&actions::FoldAtLevel(5), window, cx);
18532    }
18533
18534    pub fn fold_at_level_6(
18535        &mut self,
18536        _: &actions::FoldAtLevel6,
18537        window: &mut Window,
18538        cx: &mut Context<Self>,
18539    ) {
18540        self.fold_at_level(&actions::FoldAtLevel(6), window, cx);
18541    }
18542
18543    pub fn fold_at_level_7(
18544        &mut self,
18545        _: &actions::FoldAtLevel7,
18546        window: &mut Window,
18547        cx: &mut Context<Self>,
18548    ) {
18549        self.fold_at_level(&actions::FoldAtLevel(7), window, cx);
18550    }
18551
18552    pub fn fold_at_level_8(
18553        &mut self,
18554        _: &actions::FoldAtLevel8,
18555        window: &mut Window,
18556        cx: &mut Context<Self>,
18557    ) {
18558        self.fold_at_level(&actions::FoldAtLevel(8), window, cx);
18559    }
18560
18561    pub fn fold_at_level_9(
18562        &mut self,
18563        _: &actions::FoldAtLevel9,
18564        window: &mut Window,
18565        cx: &mut Context<Self>,
18566    ) {
18567        self.fold_at_level(&actions::FoldAtLevel(9), window, cx);
18568    }
18569
18570    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
18571        if self.buffer.read(cx).is_singleton() {
18572            let mut fold_ranges = Vec::new();
18573            let snapshot = self.buffer.read(cx).snapshot(cx);
18574
18575            for row in 0..snapshot.max_row().0 {
18576                if let Some(foldable_range) = self
18577                    .snapshot(window, cx)
18578                    .crease_for_buffer_row(MultiBufferRow(row))
18579                {
18580                    fold_ranges.push(foldable_range);
18581                }
18582            }
18583
18584            self.fold_creases(fold_ranges, true, window, cx);
18585        } else {
18586            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
18587                editor
18588                    .update_in(cx, |editor, _, cx| {
18589                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
18590                            editor.fold_buffer(buffer_id, cx);
18591                        }
18592                    })
18593                    .ok();
18594            });
18595        }
18596    }
18597
18598    pub fn fold_function_bodies(
18599        &mut self,
18600        _: &actions::FoldFunctionBodies,
18601        window: &mut Window,
18602        cx: &mut Context<Self>,
18603    ) {
18604        let snapshot = self.buffer.read(cx).snapshot(cx);
18605
18606        let ranges = snapshot
18607            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
18608            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
18609            .collect::<Vec<_>>();
18610
18611        let creases = ranges
18612            .into_iter()
18613            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
18614            .collect();
18615
18616        self.fold_creases(creases, true, window, cx);
18617    }
18618
18619    pub fn fold_recursive(
18620        &mut self,
18621        _: &actions::FoldRecursive,
18622        window: &mut Window,
18623        cx: &mut Context<Self>,
18624    ) {
18625        let mut to_fold = Vec::new();
18626        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18627        let selections = self.selections.all_adjusted(&display_map);
18628
18629        for selection in selections {
18630            let range = selection.range().sorted();
18631            let buffer_start_row = range.start.row;
18632
18633            if range.start.row != range.end.row {
18634                let mut found = false;
18635                for row in range.start.row..=range.end.row {
18636                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
18637                        found = true;
18638                        to_fold.push(crease);
18639                    }
18640                }
18641                if found {
18642                    continue;
18643                }
18644            }
18645
18646            for row in (0..=range.start.row).rev() {
18647                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
18648                    if crease.range().end.row >= buffer_start_row {
18649                        to_fold.push(crease);
18650                    } else {
18651                        break;
18652                    }
18653                }
18654            }
18655        }
18656
18657        self.fold_creases(to_fold, true, window, cx);
18658    }
18659
18660    pub fn fold_at(
18661        &mut self,
18662        buffer_row: MultiBufferRow,
18663        window: &mut Window,
18664        cx: &mut Context<Self>,
18665    ) {
18666        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18667
18668        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
18669            let autoscroll = self
18670                .selections
18671                .all::<Point>(&display_map)
18672                .iter()
18673                .any(|selection| crease.range().overlaps(&selection.range()));
18674
18675            self.fold_creases(vec![crease], autoscroll, window, cx);
18676        }
18677    }
18678
18679    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
18680        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18681            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18682            let buffer = display_map.buffer_snapshot();
18683            let selections = self.selections.all::<Point>(&display_map);
18684            let ranges = selections
18685                .iter()
18686                .map(|s| {
18687                    let range = s.display_range(&display_map).sorted();
18688                    let mut start = range.start.to_point(&display_map);
18689                    let mut end = range.end.to_point(&display_map);
18690                    start.column = 0;
18691                    end.column = buffer.line_len(MultiBufferRow(end.row));
18692                    start..end
18693                })
18694                .collect::<Vec<_>>();
18695
18696            self.unfold_ranges(&ranges, true, true, cx);
18697        } else {
18698            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18699            let buffer_ids = self
18700                .selections
18701                .disjoint_anchor_ranges()
18702                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18703                .collect::<HashSet<_>>();
18704            for buffer_id in buffer_ids {
18705                self.unfold_buffer(buffer_id, cx);
18706            }
18707        }
18708    }
18709
18710    pub fn unfold_recursive(
18711        &mut self,
18712        _: &UnfoldRecursive,
18713        _window: &mut Window,
18714        cx: &mut Context<Self>,
18715    ) {
18716        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18717        let selections = self.selections.all::<Point>(&display_map);
18718        let ranges = selections
18719            .iter()
18720            .map(|s| {
18721                let mut range = s.display_range(&display_map).sorted();
18722                *range.start.column_mut() = 0;
18723                *range.end.column_mut() = display_map.line_len(range.end.row());
18724                let start = range.start.to_point(&display_map);
18725                let end = range.end.to_point(&display_map);
18726                start..end
18727            })
18728            .collect::<Vec<_>>();
18729
18730        self.unfold_ranges(&ranges, true, true, cx);
18731    }
18732
18733    pub fn unfold_at(
18734        &mut self,
18735        buffer_row: MultiBufferRow,
18736        _window: &mut Window,
18737        cx: &mut Context<Self>,
18738    ) {
18739        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18740
18741        let intersection_range = Point::new(buffer_row.0, 0)
18742            ..Point::new(
18743                buffer_row.0,
18744                display_map.buffer_snapshot().line_len(buffer_row),
18745            );
18746
18747        let autoscroll = self
18748            .selections
18749            .all::<Point>(&display_map)
18750            .iter()
18751            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
18752
18753        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
18754    }
18755
18756    pub fn unfold_all(
18757        &mut self,
18758        _: &actions::UnfoldAll,
18759        _window: &mut Window,
18760        cx: &mut Context<Self>,
18761    ) {
18762        if self.buffer.read(cx).is_singleton() {
18763            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18764            self.unfold_ranges(&[0..display_map.buffer_snapshot().len()], true, true, cx);
18765        } else {
18766            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
18767                editor
18768                    .update(cx, |editor, cx| {
18769                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
18770                            editor.unfold_buffer(buffer_id, cx);
18771                        }
18772                    })
18773                    .ok();
18774            });
18775        }
18776    }
18777
18778    pub fn fold_selected_ranges(
18779        &mut self,
18780        _: &FoldSelectedRanges,
18781        window: &mut Window,
18782        cx: &mut Context<Self>,
18783    ) {
18784        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18785        let selections = self.selections.all_adjusted(&display_map);
18786        let ranges = selections
18787            .into_iter()
18788            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
18789            .collect::<Vec<_>>();
18790        self.fold_creases(ranges, true, window, cx);
18791    }
18792
18793    pub fn fold_ranges<T: ToOffset + Clone>(
18794        &mut self,
18795        ranges: Vec<Range<T>>,
18796        auto_scroll: bool,
18797        window: &mut Window,
18798        cx: &mut Context<Self>,
18799    ) {
18800        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18801        let ranges = ranges
18802            .into_iter()
18803            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
18804            .collect::<Vec<_>>();
18805        self.fold_creases(ranges, auto_scroll, window, cx);
18806    }
18807
18808    pub fn fold_creases<T: ToOffset + Clone>(
18809        &mut self,
18810        creases: Vec<Crease<T>>,
18811        auto_scroll: bool,
18812        _window: &mut Window,
18813        cx: &mut Context<Self>,
18814    ) {
18815        if creases.is_empty() {
18816            return;
18817        }
18818
18819        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
18820
18821        if auto_scroll {
18822            self.request_autoscroll(Autoscroll::fit(), cx);
18823        }
18824
18825        cx.notify();
18826
18827        self.scrollbar_marker_state.dirty = true;
18828        self.folds_did_change(cx);
18829    }
18830
18831    /// Removes any folds whose ranges intersect any of the given ranges.
18832    pub fn unfold_ranges<T: ToOffset + Clone>(
18833        &mut self,
18834        ranges: &[Range<T>],
18835        inclusive: bool,
18836        auto_scroll: bool,
18837        cx: &mut Context<Self>,
18838    ) {
18839        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
18840            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
18841        });
18842        self.folds_did_change(cx);
18843    }
18844
18845    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18846        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
18847            return;
18848        }
18849        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
18850        self.display_map.update(cx, |display_map, cx| {
18851            display_map.fold_buffers([buffer_id], cx)
18852        });
18853        cx.emit(EditorEvent::BufferFoldToggled {
18854            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
18855            folded: true,
18856        });
18857        cx.notify();
18858    }
18859
18860    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18861        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
18862            return;
18863        }
18864        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
18865        self.display_map.update(cx, |display_map, cx| {
18866            display_map.unfold_buffers([buffer_id], cx);
18867        });
18868        cx.emit(EditorEvent::BufferFoldToggled {
18869            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
18870            folded: false,
18871        });
18872        cx.notify();
18873    }
18874
18875    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
18876        self.display_map.read(cx).is_buffer_folded(buffer)
18877    }
18878
18879    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
18880        self.display_map.read(cx).folded_buffers()
18881    }
18882
18883    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18884        self.display_map.update(cx, |display_map, cx| {
18885            display_map.disable_header_for_buffer(buffer_id, cx);
18886        });
18887        cx.notify();
18888    }
18889
18890    /// Removes any folds with the given ranges.
18891    pub fn remove_folds_with_type<T: ToOffset + Clone>(
18892        &mut self,
18893        ranges: &[Range<T>],
18894        type_id: TypeId,
18895        auto_scroll: bool,
18896        cx: &mut Context<Self>,
18897    ) {
18898        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
18899            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
18900        });
18901        self.folds_did_change(cx);
18902    }
18903
18904    fn remove_folds_with<T: ToOffset + Clone>(
18905        &mut self,
18906        ranges: &[Range<T>],
18907        auto_scroll: bool,
18908        cx: &mut Context<Self>,
18909        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
18910    ) {
18911        if ranges.is_empty() {
18912            return;
18913        }
18914
18915        let mut buffers_affected = HashSet::default();
18916        let multi_buffer = self.buffer().read(cx);
18917        for range in ranges {
18918            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
18919                buffers_affected.insert(buffer.read(cx).remote_id());
18920            };
18921        }
18922
18923        self.display_map.update(cx, update);
18924
18925        if auto_scroll {
18926            self.request_autoscroll(Autoscroll::fit(), cx);
18927        }
18928
18929        cx.notify();
18930        self.scrollbar_marker_state.dirty = true;
18931        self.active_indent_guides_state.dirty = true;
18932    }
18933
18934    pub fn update_renderer_widths(
18935        &mut self,
18936        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
18937        cx: &mut Context<Self>,
18938    ) -> bool {
18939        self.display_map
18940            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
18941    }
18942
18943    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
18944        self.display_map.read(cx).fold_placeholder.clone()
18945    }
18946
18947    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
18948        self.buffer.update(cx, |buffer, cx| {
18949            buffer.set_all_diff_hunks_expanded(cx);
18950        });
18951    }
18952
18953    pub fn expand_all_diff_hunks(
18954        &mut self,
18955        _: &ExpandAllDiffHunks,
18956        _window: &mut Window,
18957        cx: &mut Context<Self>,
18958    ) {
18959        self.buffer.update(cx, |buffer, cx| {
18960            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
18961        });
18962    }
18963
18964    pub fn collapse_all_diff_hunks(
18965        &mut self,
18966        _: &CollapseAllDiffHunks,
18967        _window: &mut Window,
18968        cx: &mut Context<Self>,
18969    ) {
18970        self.buffer.update(cx, |buffer, cx| {
18971            buffer.collapse_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
18972        });
18973    }
18974
18975    pub fn toggle_selected_diff_hunks(
18976        &mut self,
18977        _: &ToggleSelectedDiffHunks,
18978        _window: &mut Window,
18979        cx: &mut Context<Self>,
18980    ) {
18981        let ranges: Vec<_> = self
18982            .selections
18983            .disjoint_anchors()
18984            .iter()
18985            .map(|s| s.range())
18986            .collect();
18987        self.toggle_diff_hunks_in_ranges(ranges, cx);
18988    }
18989
18990    pub fn diff_hunks_in_ranges<'a>(
18991        &'a self,
18992        ranges: &'a [Range<Anchor>],
18993        buffer: &'a MultiBufferSnapshot,
18994    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
18995        ranges.iter().flat_map(move |range| {
18996            let end_excerpt_id = range.end.excerpt_id;
18997            let range = range.to_point(buffer);
18998            let mut peek_end = range.end;
18999            if range.end.row < buffer.max_row().0 {
19000                peek_end = Point::new(range.end.row + 1, 0);
19001            }
19002            buffer
19003                .diff_hunks_in_range(range.start..peek_end)
19004                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
19005        })
19006    }
19007
19008    pub fn has_stageable_diff_hunks_in_ranges(
19009        &self,
19010        ranges: &[Range<Anchor>],
19011        snapshot: &MultiBufferSnapshot,
19012    ) -> bool {
19013        let mut hunks = self.diff_hunks_in_ranges(ranges, snapshot);
19014        hunks.any(|hunk| hunk.status().has_secondary_hunk())
19015    }
19016
19017    pub fn toggle_staged_selected_diff_hunks(
19018        &mut self,
19019        _: &::git::ToggleStaged,
19020        _: &mut Window,
19021        cx: &mut Context<Self>,
19022    ) {
19023        let snapshot = self.buffer.read(cx).snapshot(cx);
19024        let ranges: Vec<_> = self
19025            .selections
19026            .disjoint_anchors()
19027            .iter()
19028            .map(|s| s.range())
19029            .collect();
19030        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
19031        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
19032    }
19033
19034    pub fn set_render_diff_hunk_controls(
19035        &mut self,
19036        render_diff_hunk_controls: RenderDiffHunkControlsFn,
19037        cx: &mut Context<Self>,
19038    ) {
19039        self.render_diff_hunk_controls = render_diff_hunk_controls;
19040        cx.notify();
19041    }
19042
19043    pub fn stage_and_next(
19044        &mut self,
19045        _: &::git::StageAndNext,
19046        window: &mut Window,
19047        cx: &mut Context<Self>,
19048    ) {
19049        self.do_stage_or_unstage_and_next(true, window, cx);
19050    }
19051
19052    pub fn unstage_and_next(
19053        &mut self,
19054        _: &::git::UnstageAndNext,
19055        window: &mut Window,
19056        cx: &mut Context<Self>,
19057    ) {
19058        self.do_stage_or_unstage_and_next(false, window, cx);
19059    }
19060
19061    pub fn stage_or_unstage_diff_hunks(
19062        &mut self,
19063        stage: bool,
19064        ranges: Vec<Range<Anchor>>,
19065        cx: &mut Context<Self>,
19066    ) {
19067        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
19068        cx.spawn(async move |this, cx| {
19069            task.await?;
19070            this.update(cx, |this, cx| {
19071                let snapshot = this.buffer.read(cx).snapshot(cx);
19072                let chunk_by = this
19073                    .diff_hunks_in_ranges(&ranges, &snapshot)
19074                    .chunk_by(|hunk| hunk.buffer_id);
19075                for (buffer_id, hunks) in &chunk_by {
19076                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
19077                }
19078            })
19079        })
19080        .detach_and_log_err(cx);
19081    }
19082
19083    fn save_buffers_for_ranges_if_needed(
19084        &mut self,
19085        ranges: &[Range<Anchor>],
19086        cx: &mut Context<Editor>,
19087    ) -> Task<Result<()>> {
19088        let multibuffer = self.buffer.read(cx);
19089        let snapshot = multibuffer.read(cx);
19090        let buffer_ids: HashSet<_> = ranges
19091            .iter()
19092            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
19093            .collect();
19094        drop(snapshot);
19095
19096        let mut buffers = HashSet::default();
19097        for buffer_id in buffer_ids {
19098            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
19099                let buffer = buffer_entity.read(cx);
19100                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
19101                {
19102                    buffers.insert(buffer_entity);
19103                }
19104            }
19105        }
19106
19107        if let Some(project) = &self.project {
19108            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
19109        } else {
19110            Task::ready(Ok(()))
19111        }
19112    }
19113
19114    fn do_stage_or_unstage_and_next(
19115        &mut self,
19116        stage: bool,
19117        window: &mut Window,
19118        cx: &mut Context<Self>,
19119    ) {
19120        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
19121
19122        if ranges.iter().any(|range| range.start != range.end) {
19123            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
19124            return;
19125        }
19126
19127        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
19128        let snapshot = self.snapshot(window, cx);
19129        let position = self
19130            .selections
19131            .newest::<Point>(&snapshot.display_snapshot)
19132            .head();
19133        let mut row = snapshot
19134            .buffer_snapshot()
19135            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
19136            .find(|hunk| hunk.row_range.start.0 > position.row)
19137            .map(|hunk| hunk.row_range.start);
19138
19139        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
19140        // Outside of the project diff editor, wrap around to the beginning.
19141        if !all_diff_hunks_expanded {
19142            row = row.or_else(|| {
19143                snapshot
19144                    .buffer_snapshot()
19145                    .diff_hunks_in_range(Point::zero()..position)
19146                    .find(|hunk| hunk.row_range.end.0 < position.row)
19147                    .map(|hunk| hunk.row_range.start)
19148            });
19149        }
19150
19151        if let Some(row) = row {
19152            let destination = Point::new(row.0, 0);
19153            let autoscroll = Autoscroll::center();
19154
19155            self.unfold_ranges(&[destination..destination], false, false, cx);
19156            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
19157                s.select_ranges([destination..destination]);
19158            });
19159        }
19160    }
19161
19162    fn do_stage_or_unstage(
19163        &self,
19164        stage: bool,
19165        buffer_id: BufferId,
19166        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
19167        cx: &mut App,
19168    ) -> Option<()> {
19169        let project = self.project()?;
19170        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
19171        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
19172        let buffer_snapshot = buffer.read(cx).snapshot();
19173        let file_exists = buffer_snapshot
19174            .file()
19175            .is_some_and(|file| file.disk_state().exists());
19176        diff.update(cx, |diff, cx| {
19177            diff.stage_or_unstage_hunks(
19178                stage,
19179                &hunks
19180                    .map(|hunk| buffer_diff::DiffHunk {
19181                        buffer_range: hunk.buffer_range,
19182                        diff_base_byte_range: hunk.diff_base_byte_range,
19183                        secondary_status: hunk.secondary_status,
19184                        range: Point::zero()..Point::zero(), // unused
19185                    })
19186                    .collect::<Vec<_>>(),
19187                &buffer_snapshot,
19188                file_exists,
19189                cx,
19190            )
19191        });
19192        None
19193    }
19194
19195    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
19196        let ranges: Vec<_> = self
19197            .selections
19198            .disjoint_anchors()
19199            .iter()
19200            .map(|s| s.range())
19201            .collect();
19202        self.buffer
19203            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
19204    }
19205
19206    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
19207        self.buffer.update(cx, |buffer, cx| {
19208            let ranges = vec![Anchor::min()..Anchor::max()];
19209            if !buffer.all_diff_hunks_expanded()
19210                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
19211            {
19212                buffer.collapse_diff_hunks(ranges, cx);
19213                true
19214            } else {
19215                false
19216            }
19217        })
19218    }
19219
19220    fn toggle_diff_hunks_in_ranges(
19221        &mut self,
19222        ranges: Vec<Range<Anchor>>,
19223        cx: &mut Context<Editor>,
19224    ) {
19225        self.buffer.update(cx, |buffer, cx| {
19226            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
19227            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
19228        })
19229    }
19230
19231    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
19232        self.buffer.update(cx, |buffer, cx| {
19233            let snapshot = buffer.snapshot(cx);
19234            let excerpt_id = range.end.excerpt_id;
19235            let point_range = range.to_point(&snapshot);
19236            let expand = !buffer.single_hunk_is_expanded(range, cx);
19237            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
19238        })
19239    }
19240
19241    pub(crate) fn apply_all_diff_hunks(
19242        &mut self,
19243        _: &ApplyAllDiffHunks,
19244        window: &mut Window,
19245        cx: &mut Context<Self>,
19246    ) {
19247        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19248
19249        let buffers = self.buffer.read(cx).all_buffers();
19250        for branch_buffer in buffers {
19251            branch_buffer.update(cx, |branch_buffer, cx| {
19252                branch_buffer.merge_into_base(Vec::new(), cx);
19253            });
19254        }
19255
19256        if let Some(project) = self.project.clone() {
19257            self.save(
19258                SaveOptions {
19259                    format: true,
19260                    autosave: false,
19261                },
19262                project,
19263                window,
19264                cx,
19265            )
19266            .detach_and_log_err(cx);
19267        }
19268    }
19269
19270    pub(crate) fn apply_selected_diff_hunks(
19271        &mut self,
19272        _: &ApplyDiffHunk,
19273        window: &mut Window,
19274        cx: &mut Context<Self>,
19275    ) {
19276        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19277        let snapshot = self.snapshot(window, cx);
19278        let hunks = snapshot.hunks_for_ranges(
19279            self.selections
19280                .all(&snapshot.display_snapshot)
19281                .into_iter()
19282                .map(|selection| selection.range()),
19283        );
19284        let mut ranges_by_buffer = HashMap::default();
19285        self.transact(window, cx, |editor, _window, cx| {
19286            for hunk in hunks {
19287                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
19288                    ranges_by_buffer
19289                        .entry(buffer.clone())
19290                        .or_insert_with(Vec::new)
19291                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
19292                }
19293            }
19294
19295            for (buffer, ranges) in ranges_by_buffer {
19296                buffer.update(cx, |buffer, cx| {
19297                    buffer.merge_into_base(ranges, cx);
19298                });
19299            }
19300        });
19301
19302        if let Some(project) = self.project.clone() {
19303            self.save(
19304                SaveOptions {
19305                    format: true,
19306                    autosave: false,
19307                },
19308                project,
19309                window,
19310                cx,
19311            )
19312            .detach_and_log_err(cx);
19313        }
19314    }
19315
19316    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
19317        if hovered != self.gutter_hovered {
19318            self.gutter_hovered = hovered;
19319            cx.notify();
19320        }
19321    }
19322
19323    pub fn insert_blocks(
19324        &mut self,
19325        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
19326        autoscroll: Option<Autoscroll>,
19327        cx: &mut Context<Self>,
19328    ) -> Vec<CustomBlockId> {
19329        let blocks = self
19330            .display_map
19331            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
19332        if let Some(autoscroll) = autoscroll {
19333            self.request_autoscroll(autoscroll, cx);
19334        }
19335        cx.notify();
19336        blocks
19337    }
19338
19339    pub fn resize_blocks(
19340        &mut self,
19341        heights: HashMap<CustomBlockId, u32>,
19342        autoscroll: Option<Autoscroll>,
19343        cx: &mut Context<Self>,
19344    ) {
19345        self.display_map
19346            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
19347        if let Some(autoscroll) = autoscroll {
19348            self.request_autoscroll(autoscroll, cx);
19349        }
19350        cx.notify();
19351    }
19352
19353    pub fn replace_blocks(
19354        &mut self,
19355        renderers: HashMap<CustomBlockId, RenderBlock>,
19356        autoscroll: Option<Autoscroll>,
19357        cx: &mut Context<Self>,
19358    ) {
19359        self.display_map
19360            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
19361        if let Some(autoscroll) = autoscroll {
19362            self.request_autoscroll(autoscroll, cx);
19363        }
19364        cx.notify();
19365    }
19366
19367    pub fn remove_blocks(
19368        &mut self,
19369        block_ids: HashSet<CustomBlockId>,
19370        autoscroll: Option<Autoscroll>,
19371        cx: &mut Context<Self>,
19372    ) {
19373        self.display_map.update(cx, |display_map, cx| {
19374            display_map.remove_blocks(block_ids, cx)
19375        });
19376        if let Some(autoscroll) = autoscroll {
19377            self.request_autoscroll(autoscroll, cx);
19378        }
19379        cx.notify();
19380    }
19381
19382    pub fn row_for_block(
19383        &self,
19384        block_id: CustomBlockId,
19385        cx: &mut Context<Self>,
19386    ) -> Option<DisplayRow> {
19387        self.display_map
19388            .update(cx, |map, cx| map.row_for_block(block_id, cx))
19389    }
19390
19391    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
19392        self.focused_block = Some(focused_block);
19393    }
19394
19395    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
19396        self.focused_block.take()
19397    }
19398
19399    pub fn insert_creases(
19400        &mut self,
19401        creases: impl IntoIterator<Item = Crease<Anchor>>,
19402        cx: &mut Context<Self>,
19403    ) -> Vec<CreaseId> {
19404        self.display_map
19405            .update(cx, |map, cx| map.insert_creases(creases, cx))
19406    }
19407
19408    pub fn remove_creases(
19409        &mut self,
19410        ids: impl IntoIterator<Item = CreaseId>,
19411        cx: &mut Context<Self>,
19412    ) -> Vec<(CreaseId, Range<Anchor>)> {
19413        self.display_map
19414            .update(cx, |map, cx| map.remove_creases(ids, cx))
19415    }
19416
19417    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
19418        self.display_map
19419            .update(cx, |map, cx| map.snapshot(cx))
19420            .longest_row()
19421    }
19422
19423    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
19424        self.display_map
19425            .update(cx, |map, cx| map.snapshot(cx))
19426            .max_point()
19427    }
19428
19429    pub fn text(&self, cx: &App) -> String {
19430        self.buffer.read(cx).read(cx).text()
19431    }
19432
19433    pub fn is_empty(&self, cx: &App) -> bool {
19434        self.buffer.read(cx).read(cx).is_empty()
19435    }
19436
19437    pub fn text_option(&self, cx: &App) -> Option<String> {
19438        let text = self.text(cx);
19439        let text = text.trim();
19440
19441        if text.is_empty() {
19442            return None;
19443        }
19444
19445        Some(text.to_string())
19446    }
19447
19448    pub fn set_text(
19449        &mut self,
19450        text: impl Into<Arc<str>>,
19451        window: &mut Window,
19452        cx: &mut Context<Self>,
19453    ) {
19454        self.transact(window, cx, |this, _, cx| {
19455            this.buffer
19456                .read(cx)
19457                .as_singleton()
19458                .expect("you can only call set_text on editors for singleton buffers")
19459                .update(cx, |buffer, cx| buffer.set_text(text, cx));
19460        });
19461    }
19462
19463    pub fn display_text(&self, cx: &mut App) -> String {
19464        self.display_map
19465            .update(cx, |map, cx| map.snapshot(cx))
19466            .text()
19467    }
19468
19469    fn create_minimap(
19470        &self,
19471        minimap_settings: MinimapSettings,
19472        window: &mut Window,
19473        cx: &mut Context<Self>,
19474    ) -> Option<Entity<Self>> {
19475        (minimap_settings.minimap_enabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton)
19476            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
19477    }
19478
19479    fn initialize_new_minimap(
19480        &self,
19481        minimap_settings: MinimapSettings,
19482        window: &mut Window,
19483        cx: &mut Context<Self>,
19484    ) -> Entity<Self> {
19485        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
19486
19487        let mut minimap = Editor::new_internal(
19488            EditorMode::Minimap {
19489                parent: cx.weak_entity(),
19490            },
19491            self.buffer.clone(),
19492            None,
19493            Some(self.display_map.clone()),
19494            window,
19495            cx,
19496        );
19497        minimap.scroll_manager.clone_state(&self.scroll_manager);
19498        minimap.set_text_style_refinement(TextStyleRefinement {
19499            font_size: Some(MINIMAP_FONT_SIZE),
19500            font_weight: Some(MINIMAP_FONT_WEIGHT),
19501            ..Default::default()
19502        });
19503        minimap.update_minimap_configuration(minimap_settings, cx);
19504        cx.new(|_| minimap)
19505    }
19506
19507    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
19508        let current_line_highlight = minimap_settings
19509            .current_line_highlight
19510            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
19511        self.set_current_line_highlight(Some(current_line_highlight));
19512    }
19513
19514    pub fn minimap(&self) -> Option<&Entity<Self>> {
19515        self.minimap
19516            .as_ref()
19517            .filter(|_| self.minimap_visibility.visible())
19518    }
19519
19520    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
19521        let mut wrap_guides = smallvec![];
19522
19523        if self.show_wrap_guides == Some(false) {
19524            return wrap_guides;
19525        }
19526
19527        let settings = self.buffer.read(cx).language_settings(cx);
19528        if settings.show_wrap_guides {
19529            match self.soft_wrap_mode(cx) {
19530                SoftWrap::Column(soft_wrap) => {
19531                    wrap_guides.push((soft_wrap as usize, true));
19532                }
19533                SoftWrap::Bounded(soft_wrap) => {
19534                    wrap_guides.push((soft_wrap as usize, true));
19535                }
19536                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
19537            }
19538            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
19539        }
19540
19541        wrap_guides
19542    }
19543
19544    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
19545        let settings = self.buffer.read(cx).language_settings(cx);
19546        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
19547        match mode {
19548            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
19549                SoftWrap::None
19550            }
19551            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
19552            language_settings::SoftWrap::PreferredLineLength => {
19553                SoftWrap::Column(settings.preferred_line_length)
19554            }
19555            language_settings::SoftWrap::Bounded => {
19556                SoftWrap::Bounded(settings.preferred_line_length)
19557            }
19558        }
19559    }
19560
19561    pub fn set_soft_wrap_mode(
19562        &mut self,
19563        mode: language_settings::SoftWrap,
19564
19565        cx: &mut Context<Self>,
19566    ) {
19567        self.soft_wrap_mode_override = Some(mode);
19568        cx.notify();
19569    }
19570
19571    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
19572        self.hard_wrap = hard_wrap;
19573        cx.notify();
19574    }
19575
19576    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
19577        self.text_style_refinement = Some(style);
19578    }
19579
19580    /// called by the Element so we know what style we were most recently rendered with.
19581    pub fn set_style(&mut self, style: EditorStyle, window: &mut Window, cx: &mut Context<Self>) {
19582        // We intentionally do not inform the display map about the minimap style
19583        // so that wrapping is not recalculated and stays consistent for the editor
19584        // and its linked minimap.
19585        if !self.mode.is_minimap() {
19586            let font = style.text.font();
19587            let font_size = style.text.font_size.to_pixels(window.rem_size());
19588            let display_map = self
19589                .placeholder_display_map
19590                .as_ref()
19591                .filter(|_| self.is_empty(cx))
19592                .unwrap_or(&self.display_map);
19593
19594            display_map.update(cx, |map, cx| map.set_font(font, font_size, cx));
19595        }
19596        self.style = Some(style);
19597    }
19598
19599    pub fn style(&self) -> Option<&EditorStyle> {
19600        self.style.as_ref()
19601    }
19602
19603    // Called by the element. This method is not designed to be called outside of the editor
19604    // element's layout code because it does not notify when rewrapping is computed synchronously.
19605    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
19606        if self.is_empty(cx) {
19607            self.placeholder_display_map
19608                .as_ref()
19609                .map_or(false, |display_map| {
19610                    display_map.update(cx, |map, cx| map.set_wrap_width(width, cx))
19611                })
19612        } else {
19613            self.display_map
19614                .update(cx, |map, cx| map.set_wrap_width(width, cx))
19615        }
19616    }
19617
19618    pub fn set_soft_wrap(&mut self) {
19619        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
19620    }
19621
19622    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
19623        if self.soft_wrap_mode_override.is_some() {
19624            self.soft_wrap_mode_override.take();
19625        } else {
19626            let soft_wrap = match self.soft_wrap_mode(cx) {
19627                SoftWrap::GitDiff => return,
19628                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
19629                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
19630                    language_settings::SoftWrap::None
19631                }
19632            };
19633            self.soft_wrap_mode_override = Some(soft_wrap);
19634        }
19635        cx.notify();
19636    }
19637
19638    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
19639        let Some(workspace) = self.workspace() else {
19640            return;
19641        };
19642        let fs = workspace.read(cx).app_state().fs.clone();
19643        let current_show = TabBarSettings::get_global(cx).show;
19644        update_settings_file(fs, cx, move |setting, _| {
19645            setting.tab_bar.get_or_insert_default().show = Some(!current_show);
19646        });
19647    }
19648
19649    pub fn toggle_indent_guides(
19650        &mut self,
19651        _: &ToggleIndentGuides,
19652        _: &mut Window,
19653        cx: &mut Context<Self>,
19654    ) {
19655        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
19656            self.buffer
19657                .read(cx)
19658                .language_settings(cx)
19659                .indent_guides
19660                .enabled
19661        });
19662        self.show_indent_guides = Some(!currently_enabled);
19663        cx.notify();
19664    }
19665
19666    fn should_show_indent_guides(&self) -> Option<bool> {
19667        self.show_indent_guides
19668    }
19669
19670    pub fn toggle_line_numbers(
19671        &mut self,
19672        _: &ToggleLineNumbers,
19673        _: &mut Window,
19674        cx: &mut Context<Self>,
19675    ) {
19676        let mut editor_settings = EditorSettings::get_global(cx).clone();
19677        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
19678        EditorSettings::override_global(editor_settings, cx);
19679    }
19680
19681    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
19682        if let Some(show_line_numbers) = self.show_line_numbers {
19683            return show_line_numbers;
19684        }
19685        EditorSettings::get_global(cx).gutter.line_numbers
19686    }
19687
19688    pub fn relative_line_numbers(&self, cx: &mut App) -> RelativeLineNumbers {
19689        match (
19690            self.use_relative_line_numbers,
19691            EditorSettings::get_global(cx).relative_line_numbers,
19692        ) {
19693            (None, setting) => setting,
19694            (Some(false), _) => RelativeLineNumbers::Disabled,
19695            (Some(true), RelativeLineNumbers::Wrapped) => RelativeLineNumbers::Wrapped,
19696            (Some(true), _) => RelativeLineNumbers::Enabled,
19697        }
19698    }
19699
19700    pub fn toggle_relative_line_numbers(
19701        &mut self,
19702        _: &ToggleRelativeLineNumbers,
19703        _: &mut Window,
19704        cx: &mut Context<Self>,
19705    ) {
19706        let is_relative = self.relative_line_numbers(cx);
19707        self.set_relative_line_number(Some(!is_relative.enabled()), cx)
19708    }
19709
19710    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
19711        self.use_relative_line_numbers = is_relative;
19712        cx.notify();
19713    }
19714
19715    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
19716        self.show_gutter = show_gutter;
19717        cx.notify();
19718    }
19719
19720    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
19721        self.show_scrollbars = ScrollbarAxes {
19722            horizontal: show,
19723            vertical: show,
19724        };
19725        cx.notify();
19726    }
19727
19728    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
19729        self.show_scrollbars.vertical = show;
19730        cx.notify();
19731    }
19732
19733    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
19734        self.show_scrollbars.horizontal = show;
19735        cx.notify();
19736    }
19737
19738    pub fn set_minimap_visibility(
19739        &mut self,
19740        minimap_visibility: MinimapVisibility,
19741        window: &mut Window,
19742        cx: &mut Context<Self>,
19743    ) {
19744        if self.minimap_visibility != minimap_visibility {
19745            if minimap_visibility.visible() && self.minimap.is_none() {
19746                let minimap_settings = EditorSettings::get_global(cx).minimap;
19747                self.minimap =
19748                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
19749            }
19750            self.minimap_visibility = minimap_visibility;
19751            cx.notify();
19752        }
19753    }
19754
19755    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19756        self.set_show_scrollbars(false, cx);
19757        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
19758    }
19759
19760    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19761        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
19762    }
19763
19764    /// Normally the text in full mode and auto height editors is padded on the
19765    /// left side by roughly half a character width for improved hit testing.
19766    ///
19767    /// Use this method to disable this for cases where this is not wanted (e.g.
19768    /// if you want to align the editor text with some other text above or below)
19769    /// or if you want to add this padding to single-line editors.
19770    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
19771        self.offset_content = offset_content;
19772        cx.notify();
19773    }
19774
19775    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
19776        self.show_line_numbers = Some(show_line_numbers);
19777        cx.notify();
19778    }
19779
19780    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
19781        self.disable_expand_excerpt_buttons = true;
19782        cx.notify();
19783    }
19784
19785    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
19786        self.show_git_diff_gutter = Some(show_git_diff_gutter);
19787        cx.notify();
19788    }
19789
19790    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
19791        self.show_code_actions = Some(show_code_actions);
19792        cx.notify();
19793    }
19794
19795    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
19796        self.show_runnables = Some(show_runnables);
19797        cx.notify();
19798    }
19799
19800    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
19801        self.show_breakpoints = Some(show_breakpoints);
19802        cx.notify();
19803    }
19804
19805    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
19806        if self.display_map.read(cx).masked != masked {
19807            self.display_map.update(cx, |map, _| map.masked = masked);
19808        }
19809        cx.notify()
19810    }
19811
19812    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
19813        self.show_wrap_guides = Some(show_wrap_guides);
19814        cx.notify();
19815    }
19816
19817    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
19818        self.show_indent_guides = Some(show_indent_guides);
19819        cx.notify();
19820    }
19821
19822    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
19823        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
19824            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local())
19825                && let Some(dir) = file.abs_path(cx).parent()
19826            {
19827                return Some(dir.to_owned());
19828            }
19829        }
19830
19831        None
19832    }
19833
19834    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
19835        self.active_excerpt(cx)?
19836            .1
19837            .read(cx)
19838            .file()
19839            .and_then(|f| f.as_local())
19840    }
19841
19842    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
19843        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
19844            let buffer = buffer.read(cx);
19845            if let Some(project_path) = buffer.project_path(cx) {
19846                let project = self.project()?.read(cx);
19847                project.absolute_path(&project_path, cx)
19848            } else {
19849                buffer
19850                    .file()
19851                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
19852            }
19853        })
19854    }
19855
19856    pub fn reveal_in_finder(
19857        &mut self,
19858        _: &RevealInFileManager,
19859        _window: &mut Window,
19860        cx: &mut Context<Self>,
19861    ) {
19862        if let Some(target) = self.target_file(cx) {
19863            cx.reveal_path(&target.abs_path(cx));
19864        }
19865    }
19866
19867    pub fn copy_path(
19868        &mut self,
19869        _: &zed_actions::workspace::CopyPath,
19870        _window: &mut Window,
19871        cx: &mut Context<Self>,
19872    ) {
19873        if let Some(path) = self.target_file_abs_path(cx)
19874            && let Some(path) = path.to_str()
19875        {
19876            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
19877        } else {
19878            cx.propagate();
19879        }
19880    }
19881
19882    pub fn copy_relative_path(
19883        &mut self,
19884        _: &zed_actions::workspace::CopyRelativePath,
19885        _window: &mut Window,
19886        cx: &mut Context<Self>,
19887    ) {
19888        if let Some(path) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
19889            let project = self.project()?.read(cx);
19890            let path = buffer.read(cx).file()?.path();
19891            let path = path.display(project.path_style(cx));
19892            Some(path)
19893        }) {
19894            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
19895        } else {
19896            cx.propagate();
19897        }
19898    }
19899
19900    /// Returns the project path for the editor's buffer, if any buffer is
19901    /// opened in the editor.
19902    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
19903        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
19904            buffer.read(cx).project_path(cx)
19905        } else {
19906            None
19907        }
19908    }
19909
19910    // Returns true if the editor handled a go-to-line request
19911    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
19912        maybe!({
19913            let breakpoint_store = self.breakpoint_store.as_ref()?;
19914
19915            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
19916            else {
19917                self.clear_row_highlights::<ActiveDebugLine>();
19918                return None;
19919            };
19920
19921            let position = active_stack_frame.position;
19922            let buffer_id = position.buffer_id?;
19923            let snapshot = self
19924                .project
19925                .as_ref()?
19926                .read(cx)
19927                .buffer_for_id(buffer_id, cx)?
19928                .read(cx)
19929                .snapshot();
19930
19931            let mut handled = false;
19932            for (id, ExcerptRange { context, .. }) in
19933                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
19934            {
19935                if context.start.cmp(&position, &snapshot).is_ge()
19936                    || context.end.cmp(&position, &snapshot).is_lt()
19937                {
19938                    continue;
19939                }
19940                let snapshot = self.buffer.read(cx).snapshot(cx);
19941                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
19942
19943                handled = true;
19944                self.clear_row_highlights::<ActiveDebugLine>();
19945
19946                self.go_to_line::<ActiveDebugLine>(
19947                    multibuffer_anchor,
19948                    Some(cx.theme().colors().editor_debugger_active_line_background),
19949                    window,
19950                    cx,
19951                );
19952
19953                cx.notify();
19954            }
19955
19956            handled.then_some(())
19957        })
19958        .is_some()
19959    }
19960
19961    pub fn copy_file_name_without_extension(
19962        &mut self,
19963        _: &CopyFileNameWithoutExtension,
19964        _: &mut Window,
19965        cx: &mut Context<Self>,
19966    ) {
19967        if let Some(file) = self.target_file(cx)
19968            && let Some(file_stem) = file.path().file_stem()
19969        {
19970            cx.write_to_clipboard(ClipboardItem::new_string(file_stem.to_string()));
19971        }
19972    }
19973
19974    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
19975        if let Some(file) = self.target_file(cx)
19976            && let Some(name) = file.path().file_name()
19977        {
19978            cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
19979        }
19980    }
19981
19982    pub fn toggle_git_blame(
19983        &mut self,
19984        _: &::git::Blame,
19985        window: &mut Window,
19986        cx: &mut Context<Self>,
19987    ) {
19988        self.show_git_blame_gutter = !self.show_git_blame_gutter;
19989
19990        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
19991            self.start_git_blame(true, window, cx);
19992        }
19993
19994        cx.notify();
19995    }
19996
19997    pub fn toggle_git_blame_inline(
19998        &mut self,
19999        _: &ToggleGitBlameInline,
20000        window: &mut Window,
20001        cx: &mut Context<Self>,
20002    ) {
20003        self.toggle_git_blame_inline_internal(true, window, cx);
20004        cx.notify();
20005    }
20006
20007    pub fn open_git_blame_commit(
20008        &mut self,
20009        _: &OpenGitBlameCommit,
20010        window: &mut Window,
20011        cx: &mut Context<Self>,
20012    ) {
20013        self.open_git_blame_commit_internal(window, cx);
20014    }
20015
20016    fn open_git_blame_commit_internal(
20017        &mut self,
20018        window: &mut Window,
20019        cx: &mut Context<Self>,
20020    ) -> Option<()> {
20021        let blame = self.blame.as_ref()?;
20022        let snapshot = self.snapshot(window, cx);
20023        let cursor = self
20024            .selections
20025            .newest::<Point>(&snapshot.display_snapshot)
20026            .head();
20027        let (buffer, point, _) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)?;
20028        let (_, blame_entry) = blame
20029            .update(cx, |blame, cx| {
20030                blame
20031                    .blame_for_rows(
20032                        &[RowInfo {
20033                            buffer_id: Some(buffer.remote_id()),
20034                            buffer_row: Some(point.row),
20035                            ..Default::default()
20036                        }],
20037                        cx,
20038                    )
20039                    .next()
20040            })
20041            .flatten()?;
20042        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
20043        let repo = blame.read(cx).repository(cx, buffer.remote_id())?;
20044        let workspace = self.workspace()?.downgrade();
20045        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
20046        None
20047    }
20048
20049    pub fn git_blame_inline_enabled(&self) -> bool {
20050        self.git_blame_inline_enabled
20051    }
20052
20053    pub fn toggle_selection_menu(
20054        &mut self,
20055        _: &ToggleSelectionMenu,
20056        _: &mut Window,
20057        cx: &mut Context<Self>,
20058    ) {
20059        self.show_selection_menu = self
20060            .show_selection_menu
20061            .map(|show_selections_menu| !show_selections_menu)
20062            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
20063
20064        cx.notify();
20065    }
20066
20067    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
20068        self.show_selection_menu
20069            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
20070    }
20071
20072    fn start_git_blame(
20073        &mut self,
20074        user_triggered: bool,
20075        window: &mut Window,
20076        cx: &mut Context<Self>,
20077    ) {
20078        if let Some(project) = self.project() {
20079            if let Some(buffer) = self.buffer().read(cx).as_singleton()
20080                && buffer.read(cx).file().is_none()
20081            {
20082                return;
20083            }
20084
20085            let focused = self.focus_handle(cx).contains_focused(window, cx);
20086
20087            let project = project.clone();
20088            let blame = cx
20089                .new(|cx| GitBlame::new(self.buffer.clone(), project, user_triggered, focused, cx));
20090            self.blame_subscription =
20091                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
20092            self.blame = Some(blame);
20093        }
20094    }
20095
20096    fn toggle_git_blame_inline_internal(
20097        &mut self,
20098        user_triggered: bool,
20099        window: &mut Window,
20100        cx: &mut Context<Self>,
20101    ) {
20102        if self.git_blame_inline_enabled {
20103            self.git_blame_inline_enabled = false;
20104            self.show_git_blame_inline = false;
20105            self.show_git_blame_inline_delay_task.take();
20106        } else {
20107            self.git_blame_inline_enabled = true;
20108            self.start_git_blame_inline(user_triggered, window, cx);
20109        }
20110
20111        cx.notify();
20112    }
20113
20114    fn start_git_blame_inline(
20115        &mut self,
20116        user_triggered: bool,
20117        window: &mut Window,
20118        cx: &mut Context<Self>,
20119    ) {
20120        self.start_git_blame(user_triggered, window, cx);
20121
20122        if ProjectSettings::get_global(cx)
20123            .git
20124            .inline_blame_delay()
20125            .is_some()
20126        {
20127            self.start_inline_blame_timer(window, cx);
20128        } else {
20129            self.show_git_blame_inline = true
20130        }
20131    }
20132
20133    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
20134        self.blame.as_ref()
20135    }
20136
20137    pub fn show_git_blame_gutter(&self) -> bool {
20138        self.show_git_blame_gutter
20139    }
20140
20141    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
20142        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
20143    }
20144
20145    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
20146        self.show_git_blame_inline
20147            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
20148            && !self.newest_selection_head_on_empty_line(cx)
20149            && self.has_blame_entries(cx)
20150    }
20151
20152    fn has_blame_entries(&self, cx: &App) -> bool {
20153        self.blame()
20154            .is_some_and(|blame| blame.read(cx).has_generated_entries())
20155    }
20156
20157    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
20158        let cursor_anchor = self.selections.newest_anchor().head();
20159
20160        let snapshot = self.buffer.read(cx).snapshot(cx);
20161        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
20162
20163        snapshot.line_len(buffer_row) == 0
20164    }
20165
20166    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
20167        let buffer_and_selection = maybe!({
20168            let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
20169            let selection_range = selection.range();
20170
20171            let multi_buffer = self.buffer().read(cx);
20172            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
20173            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
20174
20175            let (buffer, range, _) = if selection.reversed {
20176                buffer_ranges.first()
20177            } else {
20178                buffer_ranges.last()
20179            }?;
20180
20181            let selection = text::ToPoint::to_point(&range.start, buffer).row
20182                ..text::ToPoint::to_point(&range.end, buffer).row;
20183            Some((multi_buffer.buffer(buffer.remote_id()).unwrap(), selection))
20184        });
20185
20186        let Some((buffer, selection)) = buffer_and_selection else {
20187            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
20188        };
20189
20190        let Some(project) = self.project() else {
20191            return Task::ready(Err(anyhow!("editor does not have project")));
20192        };
20193
20194        project.update(cx, |project, cx| {
20195            project.get_permalink_to_line(&buffer, selection, cx)
20196        })
20197    }
20198
20199    pub fn copy_permalink_to_line(
20200        &mut self,
20201        _: &CopyPermalinkToLine,
20202        window: &mut Window,
20203        cx: &mut Context<Self>,
20204    ) {
20205        let permalink_task = self.get_permalink_to_line(cx);
20206        let workspace = self.workspace();
20207
20208        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
20209            Ok(permalink) => {
20210                cx.update(|_, cx| {
20211                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
20212                })
20213                .ok();
20214            }
20215            Err(err) => {
20216                let message = format!("Failed to copy permalink: {err}");
20217
20218                anyhow::Result::<()>::Err(err).log_err();
20219
20220                if let Some(workspace) = workspace {
20221                    workspace
20222                        .update_in(cx, |workspace, _, cx| {
20223                            struct CopyPermalinkToLine;
20224
20225                            workspace.show_toast(
20226                                Toast::new(
20227                                    NotificationId::unique::<CopyPermalinkToLine>(),
20228                                    message,
20229                                ),
20230                                cx,
20231                            )
20232                        })
20233                        .ok();
20234                }
20235            }
20236        })
20237        .detach();
20238    }
20239
20240    pub fn copy_file_location(
20241        &mut self,
20242        _: &CopyFileLocation,
20243        _: &mut Window,
20244        cx: &mut Context<Self>,
20245    ) {
20246        let selection = self
20247            .selections
20248            .newest::<Point>(&self.display_snapshot(cx))
20249            .start
20250            .row
20251            + 1;
20252        if let Some(file) = self.target_file(cx) {
20253            let path = file.path().display(file.path_style(cx));
20254            cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
20255        }
20256    }
20257
20258    pub fn open_permalink_to_line(
20259        &mut self,
20260        _: &OpenPermalinkToLine,
20261        window: &mut Window,
20262        cx: &mut Context<Self>,
20263    ) {
20264        let permalink_task = self.get_permalink_to_line(cx);
20265        let workspace = self.workspace();
20266
20267        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
20268            Ok(permalink) => {
20269                cx.update(|_, cx| {
20270                    cx.open_url(permalink.as_ref());
20271                })
20272                .ok();
20273            }
20274            Err(err) => {
20275                let message = format!("Failed to open permalink: {err}");
20276
20277                anyhow::Result::<()>::Err(err).log_err();
20278
20279                if let Some(workspace) = workspace {
20280                    workspace
20281                        .update(cx, |workspace, cx| {
20282                            struct OpenPermalinkToLine;
20283
20284                            workspace.show_toast(
20285                                Toast::new(
20286                                    NotificationId::unique::<OpenPermalinkToLine>(),
20287                                    message,
20288                                ),
20289                                cx,
20290                            )
20291                        })
20292                        .ok();
20293                }
20294            }
20295        })
20296        .detach();
20297    }
20298
20299    pub fn insert_uuid_v4(
20300        &mut self,
20301        _: &InsertUuidV4,
20302        window: &mut Window,
20303        cx: &mut Context<Self>,
20304    ) {
20305        self.insert_uuid(UuidVersion::V4, window, cx);
20306    }
20307
20308    pub fn insert_uuid_v7(
20309        &mut self,
20310        _: &InsertUuidV7,
20311        window: &mut Window,
20312        cx: &mut Context<Self>,
20313    ) {
20314        self.insert_uuid(UuidVersion::V7, window, cx);
20315    }
20316
20317    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
20318        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
20319        self.transact(window, cx, |this, window, cx| {
20320            let edits = this
20321                .selections
20322                .all::<Point>(&this.display_snapshot(cx))
20323                .into_iter()
20324                .map(|selection| {
20325                    let uuid = match version {
20326                        UuidVersion::V4 => uuid::Uuid::new_v4(),
20327                        UuidVersion::V7 => uuid::Uuid::now_v7(),
20328                    };
20329
20330                    (selection.range(), uuid.to_string())
20331                });
20332            this.edit(edits, cx);
20333            this.refresh_edit_prediction(true, false, window, cx);
20334        });
20335    }
20336
20337    pub fn open_selections_in_multibuffer(
20338        &mut self,
20339        _: &OpenSelectionsInMultibuffer,
20340        window: &mut Window,
20341        cx: &mut Context<Self>,
20342    ) {
20343        let multibuffer = self.buffer.read(cx);
20344
20345        let Some(buffer) = multibuffer.as_singleton() else {
20346            return;
20347        };
20348
20349        let Some(workspace) = self.workspace() else {
20350            return;
20351        };
20352
20353        let title = multibuffer.title(cx).to_string();
20354
20355        let locations = self
20356            .selections
20357            .all_anchors(&self.display_snapshot(cx))
20358            .iter()
20359            .map(|selection| {
20360                (
20361                    buffer.clone(),
20362                    (selection.start.text_anchor..selection.end.text_anchor)
20363                        .to_point(buffer.read(cx)),
20364                )
20365            })
20366            .into_group_map();
20367
20368        cx.spawn_in(window, async move |_, cx| {
20369            workspace.update_in(cx, |workspace, window, cx| {
20370                Self::open_locations_in_multibuffer(
20371                    workspace,
20372                    locations,
20373                    format!("Selections for '{title}'"),
20374                    false,
20375                    MultibufferSelectionMode::All,
20376                    window,
20377                    cx,
20378                );
20379            })
20380        })
20381        .detach();
20382    }
20383
20384    /// Adds a row highlight for the given range. If a row has multiple highlights, the
20385    /// last highlight added will be used.
20386    ///
20387    /// If the range ends at the beginning of a line, then that line will not be highlighted.
20388    pub fn highlight_rows<T: 'static>(
20389        &mut self,
20390        range: Range<Anchor>,
20391        color: Hsla,
20392        options: RowHighlightOptions,
20393        cx: &mut Context<Self>,
20394    ) {
20395        let snapshot = self.buffer().read(cx).snapshot(cx);
20396        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
20397        let ix = row_highlights.binary_search_by(|highlight| {
20398            Ordering::Equal
20399                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
20400                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
20401        });
20402
20403        if let Err(mut ix) = ix {
20404            let index = post_inc(&mut self.highlight_order);
20405
20406            // If this range intersects with the preceding highlight, then merge it with
20407            // the preceding highlight. Otherwise insert a new highlight.
20408            let mut merged = false;
20409            if ix > 0 {
20410                let prev_highlight = &mut row_highlights[ix - 1];
20411                if prev_highlight
20412                    .range
20413                    .end
20414                    .cmp(&range.start, &snapshot)
20415                    .is_ge()
20416                {
20417                    ix -= 1;
20418                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
20419                        prev_highlight.range.end = range.end;
20420                    }
20421                    merged = true;
20422                    prev_highlight.index = index;
20423                    prev_highlight.color = color;
20424                    prev_highlight.options = options;
20425                }
20426            }
20427
20428            if !merged {
20429                row_highlights.insert(
20430                    ix,
20431                    RowHighlight {
20432                        range,
20433                        index,
20434                        color,
20435                        options,
20436                        type_id: TypeId::of::<T>(),
20437                    },
20438                );
20439            }
20440
20441            // If any of the following highlights intersect with this one, merge them.
20442            while let Some(next_highlight) = row_highlights.get(ix + 1) {
20443                let highlight = &row_highlights[ix];
20444                if next_highlight
20445                    .range
20446                    .start
20447                    .cmp(&highlight.range.end, &snapshot)
20448                    .is_le()
20449                {
20450                    if next_highlight
20451                        .range
20452                        .end
20453                        .cmp(&highlight.range.end, &snapshot)
20454                        .is_gt()
20455                    {
20456                        row_highlights[ix].range.end = next_highlight.range.end;
20457                    }
20458                    row_highlights.remove(ix + 1);
20459                } else {
20460                    break;
20461                }
20462            }
20463        }
20464    }
20465
20466    /// Remove any highlighted row ranges of the given type that intersect the
20467    /// given ranges.
20468    pub fn remove_highlighted_rows<T: 'static>(
20469        &mut self,
20470        ranges_to_remove: Vec<Range<Anchor>>,
20471        cx: &mut Context<Self>,
20472    ) {
20473        let snapshot = self.buffer().read(cx).snapshot(cx);
20474        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
20475        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
20476        row_highlights.retain(|highlight| {
20477            while let Some(range_to_remove) = ranges_to_remove.peek() {
20478                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
20479                    Ordering::Less | Ordering::Equal => {
20480                        ranges_to_remove.next();
20481                    }
20482                    Ordering::Greater => {
20483                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
20484                            Ordering::Less | Ordering::Equal => {
20485                                return false;
20486                            }
20487                            Ordering::Greater => break,
20488                        }
20489                    }
20490                }
20491            }
20492
20493            true
20494        })
20495    }
20496
20497    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
20498    pub fn clear_row_highlights<T: 'static>(&mut self) {
20499        self.highlighted_rows.remove(&TypeId::of::<T>());
20500    }
20501
20502    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
20503    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
20504        self.highlighted_rows
20505            .get(&TypeId::of::<T>())
20506            .map_or(&[] as &[_], |vec| vec.as_slice())
20507            .iter()
20508            .map(|highlight| (highlight.range.clone(), highlight.color))
20509    }
20510
20511    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
20512    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
20513    /// Allows to ignore certain kinds of highlights.
20514    pub fn highlighted_display_rows(
20515        &self,
20516        window: &mut Window,
20517        cx: &mut App,
20518    ) -> BTreeMap<DisplayRow, LineHighlight> {
20519        let snapshot = self.snapshot(window, cx);
20520        let mut used_highlight_orders = HashMap::default();
20521        self.highlighted_rows
20522            .iter()
20523            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
20524            .fold(
20525                BTreeMap::<DisplayRow, LineHighlight>::new(),
20526                |mut unique_rows, highlight| {
20527                    let start = highlight.range.start.to_display_point(&snapshot);
20528                    let end = highlight.range.end.to_display_point(&snapshot);
20529                    let start_row = start.row().0;
20530                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
20531                        && end.column() == 0
20532                    {
20533                        end.row().0.saturating_sub(1)
20534                    } else {
20535                        end.row().0
20536                    };
20537                    for row in start_row..=end_row {
20538                        let used_index =
20539                            used_highlight_orders.entry(row).or_insert(highlight.index);
20540                        if highlight.index >= *used_index {
20541                            *used_index = highlight.index;
20542                            unique_rows.insert(
20543                                DisplayRow(row),
20544                                LineHighlight {
20545                                    include_gutter: highlight.options.include_gutter,
20546                                    border: None,
20547                                    background: highlight.color.into(),
20548                                    type_id: Some(highlight.type_id),
20549                                },
20550                            );
20551                        }
20552                    }
20553                    unique_rows
20554                },
20555            )
20556    }
20557
20558    pub fn highlighted_display_row_for_autoscroll(
20559        &self,
20560        snapshot: &DisplaySnapshot,
20561    ) -> Option<DisplayRow> {
20562        self.highlighted_rows
20563            .values()
20564            .flat_map(|highlighted_rows| highlighted_rows.iter())
20565            .filter_map(|highlight| {
20566                if highlight.options.autoscroll {
20567                    Some(highlight.range.start.to_display_point(snapshot).row())
20568                } else {
20569                    None
20570                }
20571            })
20572            .min()
20573    }
20574
20575    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
20576        self.highlight_background::<SearchWithinRange>(
20577            ranges,
20578            |colors| colors.colors().editor_document_highlight_read_background,
20579            cx,
20580        )
20581    }
20582
20583    pub fn set_breadcrumb_header(&mut self, new_header: String) {
20584        self.breadcrumb_header = Some(new_header);
20585    }
20586
20587    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
20588        self.clear_background_highlights::<SearchWithinRange>(cx);
20589    }
20590
20591    pub fn highlight_background<T: 'static>(
20592        &mut self,
20593        ranges: &[Range<Anchor>],
20594        color_fetcher: fn(&Theme) -> Hsla,
20595        cx: &mut Context<Self>,
20596    ) {
20597        self.background_highlights.insert(
20598            HighlightKey::Type(TypeId::of::<T>()),
20599            (color_fetcher, Arc::from(ranges)),
20600        );
20601        self.scrollbar_marker_state.dirty = true;
20602        cx.notify();
20603    }
20604
20605    pub fn highlight_background_key<T: 'static>(
20606        &mut self,
20607        key: usize,
20608        ranges: &[Range<Anchor>],
20609        color_fetcher: fn(&Theme) -> Hsla,
20610        cx: &mut Context<Self>,
20611    ) {
20612        self.background_highlights.insert(
20613            HighlightKey::TypePlus(TypeId::of::<T>(), key),
20614            (color_fetcher, Arc::from(ranges)),
20615        );
20616        self.scrollbar_marker_state.dirty = true;
20617        cx.notify();
20618    }
20619
20620    pub fn clear_background_highlights<T: 'static>(
20621        &mut self,
20622        cx: &mut Context<Self>,
20623    ) -> Option<BackgroundHighlight> {
20624        let text_highlights = self
20625            .background_highlights
20626            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
20627        if !text_highlights.1.is_empty() {
20628            self.scrollbar_marker_state.dirty = true;
20629            cx.notify();
20630        }
20631        Some(text_highlights)
20632    }
20633
20634    pub fn highlight_gutter<T: 'static>(
20635        &mut self,
20636        ranges: impl Into<Vec<Range<Anchor>>>,
20637        color_fetcher: fn(&App) -> Hsla,
20638        cx: &mut Context<Self>,
20639    ) {
20640        self.gutter_highlights
20641            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
20642        cx.notify();
20643    }
20644
20645    pub fn clear_gutter_highlights<T: 'static>(
20646        &mut self,
20647        cx: &mut Context<Self>,
20648    ) -> Option<GutterHighlight> {
20649        cx.notify();
20650        self.gutter_highlights.remove(&TypeId::of::<T>())
20651    }
20652
20653    pub fn insert_gutter_highlight<T: 'static>(
20654        &mut self,
20655        range: Range<Anchor>,
20656        color_fetcher: fn(&App) -> Hsla,
20657        cx: &mut Context<Self>,
20658    ) {
20659        let snapshot = self.buffer().read(cx).snapshot(cx);
20660        let mut highlights = self
20661            .gutter_highlights
20662            .remove(&TypeId::of::<T>())
20663            .map(|(_, highlights)| highlights)
20664            .unwrap_or_default();
20665        let ix = highlights.binary_search_by(|highlight| {
20666            Ordering::Equal
20667                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
20668                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
20669        });
20670        if let Err(ix) = ix {
20671            highlights.insert(ix, range);
20672        }
20673        self.gutter_highlights
20674            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
20675    }
20676
20677    pub fn remove_gutter_highlights<T: 'static>(
20678        &mut self,
20679        ranges_to_remove: Vec<Range<Anchor>>,
20680        cx: &mut Context<Self>,
20681    ) {
20682        let snapshot = self.buffer().read(cx).snapshot(cx);
20683        let Some((color_fetcher, mut gutter_highlights)) =
20684            self.gutter_highlights.remove(&TypeId::of::<T>())
20685        else {
20686            return;
20687        };
20688        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
20689        gutter_highlights.retain(|highlight| {
20690            while let Some(range_to_remove) = ranges_to_remove.peek() {
20691                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
20692                    Ordering::Less | Ordering::Equal => {
20693                        ranges_to_remove.next();
20694                    }
20695                    Ordering::Greater => {
20696                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
20697                            Ordering::Less | Ordering::Equal => {
20698                                return false;
20699                            }
20700                            Ordering::Greater => break,
20701                        }
20702                    }
20703                }
20704            }
20705
20706            true
20707        });
20708        self.gutter_highlights
20709            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
20710    }
20711
20712    #[cfg(feature = "test-support")]
20713    pub fn all_text_highlights(
20714        &self,
20715        window: &mut Window,
20716        cx: &mut Context<Self>,
20717    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
20718        let snapshot = self.snapshot(window, cx);
20719        self.display_map.update(cx, |display_map, _| {
20720            display_map
20721                .all_text_highlights()
20722                .map(|highlight| {
20723                    let (style, ranges) = highlight.as_ref();
20724                    (
20725                        *style,
20726                        ranges
20727                            .iter()
20728                            .map(|range| range.clone().to_display_points(&snapshot))
20729                            .collect(),
20730                    )
20731                })
20732                .collect()
20733        })
20734    }
20735
20736    #[cfg(feature = "test-support")]
20737    pub fn all_text_background_highlights(
20738        &self,
20739        window: &mut Window,
20740        cx: &mut Context<Self>,
20741    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20742        let snapshot = self.snapshot(window, cx);
20743        let buffer = &snapshot.buffer_snapshot();
20744        let start = buffer.anchor_before(0);
20745        let end = buffer.anchor_after(buffer.len());
20746        self.sorted_background_highlights_in_range(start..end, &snapshot, cx.theme())
20747    }
20748
20749    #[cfg(any(test, feature = "test-support"))]
20750    pub fn sorted_background_highlights_in_range(
20751        &self,
20752        search_range: Range<Anchor>,
20753        display_snapshot: &DisplaySnapshot,
20754        theme: &Theme,
20755    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20756        let mut res = self.background_highlights_in_range(search_range, display_snapshot, theme);
20757        res.sort_by(|a, b| {
20758            a.0.start
20759                .cmp(&b.0.start)
20760                .then_with(|| a.0.end.cmp(&b.0.end))
20761                .then_with(|| a.1.cmp(&b.1))
20762        });
20763        res
20764    }
20765
20766    #[cfg(feature = "test-support")]
20767    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
20768        let snapshot = self.buffer().read(cx).snapshot(cx);
20769
20770        let highlights = self
20771            .background_highlights
20772            .get(&HighlightKey::Type(TypeId::of::<
20773                items::BufferSearchHighlights,
20774            >()));
20775
20776        if let Some((_color, ranges)) = highlights {
20777            ranges
20778                .iter()
20779                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
20780                .collect_vec()
20781        } else {
20782            vec![]
20783        }
20784    }
20785
20786    fn document_highlights_for_position<'a>(
20787        &'a self,
20788        position: Anchor,
20789        buffer: &'a MultiBufferSnapshot,
20790    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
20791        let read_highlights = self
20792            .background_highlights
20793            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
20794            .map(|h| &h.1);
20795        let write_highlights = self
20796            .background_highlights
20797            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
20798            .map(|h| &h.1);
20799        let left_position = position.bias_left(buffer);
20800        let right_position = position.bias_right(buffer);
20801        read_highlights
20802            .into_iter()
20803            .chain(write_highlights)
20804            .flat_map(move |ranges| {
20805                let start_ix = match ranges.binary_search_by(|probe| {
20806                    let cmp = probe.end.cmp(&left_position, buffer);
20807                    if cmp.is_ge() {
20808                        Ordering::Greater
20809                    } else {
20810                        Ordering::Less
20811                    }
20812                }) {
20813                    Ok(i) | Err(i) => i,
20814                };
20815
20816                ranges[start_ix..]
20817                    .iter()
20818                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
20819            })
20820    }
20821
20822    pub fn has_background_highlights<T: 'static>(&self) -> bool {
20823        self.background_highlights
20824            .get(&HighlightKey::Type(TypeId::of::<T>()))
20825            .is_some_and(|(_, highlights)| !highlights.is_empty())
20826    }
20827
20828    /// Returns all background highlights for a given range.
20829    ///
20830    /// The order of highlights is not deterministic, do sort the ranges if needed for the logic.
20831    pub fn background_highlights_in_range(
20832        &self,
20833        search_range: Range<Anchor>,
20834        display_snapshot: &DisplaySnapshot,
20835        theme: &Theme,
20836    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20837        let mut results = Vec::new();
20838        for (color_fetcher, ranges) in self.background_highlights.values() {
20839            let color = color_fetcher(theme);
20840            let start_ix = match ranges.binary_search_by(|probe| {
20841                let cmp = probe
20842                    .end
20843                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
20844                if cmp.is_gt() {
20845                    Ordering::Greater
20846                } else {
20847                    Ordering::Less
20848                }
20849            }) {
20850                Ok(i) | Err(i) => i,
20851            };
20852            for range in &ranges[start_ix..] {
20853                if range
20854                    .start
20855                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
20856                    .is_ge()
20857                {
20858                    break;
20859                }
20860
20861                let start = range.start.to_display_point(display_snapshot);
20862                let end = range.end.to_display_point(display_snapshot);
20863                results.push((start..end, color))
20864            }
20865        }
20866        results
20867    }
20868
20869    pub fn gutter_highlights_in_range(
20870        &self,
20871        search_range: Range<Anchor>,
20872        display_snapshot: &DisplaySnapshot,
20873        cx: &App,
20874    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20875        let mut results = Vec::new();
20876        for (color_fetcher, ranges) in self.gutter_highlights.values() {
20877            let color = color_fetcher(cx);
20878            let start_ix = match ranges.binary_search_by(|probe| {
20879                let cmp = probe
20880                    .end
20881                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
20882                if cmp.is_gt() {
20883                    Ordering::Greater
20884                } else {
20885                    Ordering::Less
20886                }
20887            }) {
20888                Ok(i) | Err(i) => i,
20889            };
20890            for range in &ranges[start_ix..] {
20891                if range
20892                    .start
20893                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
20894                    .is_ge()
20895                {
20896                    break;
20897                }
20898
20899                let start = range.start.to_display_point(display_snapshot);
20900                let end = range.end.to_display_point(display_snapshot);
20901                results.push((start..end, color))
20902            }
20903        }
20904        results
20905    }
20906
20907    /// Get the text ranges corresponding to the redaction query
20908    pub fn redacted_ranges(
20909        &self,
20910        search_range: Range<Anchor>,
20911        display_snapshot: &DisplaySnapshot,
20912        cx: &App,
20913    ) -> Vec<Range<DisplayPoint>> {
20914        display_snapshot
20915            .buffer_snapshot()
20916            .redacted_ranges(search_range, |file| {
20917                if let Some(file) = file {
20918                    file.is_private()
20919                        && EditorSettings::get(
20920                            Some(SettingsLocation {
20921                                worktree_id: file.worktree_id(cx),
20922                                path: file.path().as_ref(),
20923                            }),
20924                            cx,
20925                        )
20926                        .redact_private_values
20927                } else {
20928                    false
20929                }
20930            })
20931            .map(|range| {
20932                range.start.to_display_point(display_snapshot)
20933                    ..range.end.to_display_point(display_snapshot)
20934            })
20935            .collect()
20936    }
20937
20938    pub fn highlight_text_key<T: 'static>(
20939        &mut self,
20940        key: usize,
20941        ranges: Vec<Range<Anchor>>,
20942        style: HighlightStyle,
20943        cx: &mut Context<Self>,
20944    ) {
20945        self.display_map.update(cx, |map, _| {
20946            map.highlight_text(
20947                HighlightKey::TypePlus(TypeId::of::<T>(), key),
20948                ranges,
20949                style,
20950            );
20951        });
20952        cx.notify();
20953    }
20954
20955    pub fn highlight_text<T: 'static>(
20956        &mut self,
20957        ranges: Vec<Range<Anchor>>,
20958        style: HighlightStyle,
20959        cx: &mut Context<Self>,
20960    ) {
20961        self.display_map.update(cx, |map, _| {
20962            map.highlight_text(HighlightKey::Type(TypeId::of::<T>()), ranges, style)
20963        });
20964        cx.notify();
20965    }
20966
20967    pub fn text_highlights<'a, T: 'static>(
20968        &'a self,
20969        cx: &'a App,
20970    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
20971        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
20972    }
20973
20974    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
20975        let cleared = self
20976            .display_map
20977            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
20978        if cleared {
20979            cx.notify();
20980        }
20981    }
20982
20983    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
20984        (self.read_only(cx) || self.blink_manager.read(cx).visible())
20985            && self.focus_handle.is_focused(window)
20986    }
20987
20988    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
20989        self.show_cursor_when_unfocused = is_enabled;
20990        cx.notify();
20991    }
20992
20993    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
20994        cx.notify();
20995    }
20996
20997    fn on_debug_session_event(
20998        &mut self,
20999        _session: Entity<Session>,
21000        event: &SessionEvent,
21001        cx: &mut Context<Self>,
21002    ) {
21003        if let SessionEvent::InvalidateInlineValue = event {
21004            self.refresh_inline_values(cx);
21005        }
21006    }
21007
21008    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
21009        let Some(project) = self.project.clone() else {
21010            return;
21011        };
21012
21013        if !self.inline_value_cache.enabled {
21014            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
21015            self.splice_inlays(&inlays, Vec::new(), cx);
21016            return;
21017        }
21018
21019        let current_execution_position = self
21020            .highlighted_rows
21021            .get(&TypeId::of::<ActiveDebugLine>())
21022            .and_then(|lines| lines.last().map(|line| line.range.end));
21023
21024        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
21025            let inline_values = editor
21026                .update(cx, |editor, cx| {
21027                    let Some(current_execution_position) = current_execution_position else {
21028                        return Some(Task::ready(Ok(Vec::new())));
21029                    };
21030
21031                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
21032                        let snapshot = buffer.snapshot(cx);
21033
21034                        let excerpt = snapshot.excerpt_containing(
21035                            current_execution_position..current_execution_position,
21036                        )?;
21037
21038                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
21039                    })?;
21040
21041                    let range =
21042                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
21043
21044                    project.inline_values(buffer, range, cx)
21045                })
21046                .ok()
21047                .flatten()?
21048                .await
21049                .context("refreshing debugger inlays")
21050                .log_err()?;
21051
21052            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
21053
21054            for (buffer_id, inline_value) in inline_values
21055                .into_iter()
21056                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
21057            {
21058                buffer_inline_values
21059                    .entry(buffer_id)
21060                    .or_default()
21061                    .push(inline_value);
21062            }
21063
21064            editor
21065                .update(cx, |editor, cx| {
21066                    let snapshot = editor.buffer.read(cx).snapshot(cx);
21067                    let mut new_inlays = Vec::default();
21068
21069                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
21070                        let buffer_id = buffer_snapshot.remote_id();
21071                        buffer_inline_values
21072                            .get(&buffer_id)
21073                            .into_iter()
21074                            .flatten()
21075                            .for_each(|hint| {
21076                                let inlay = Inlay::debugger(
21077                                    post_inc(&mut editor.next_inlay_id),
21078                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
21079                                    hint.text(),
21080                                );
21081                                if !inlay.text().chars().contains(&'\n') {
21082                                    new_inlays.push(inlay);
21083                                }
21084                            });
21085                    }
21086
21087                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
21088                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
21089
21090                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
21091                })
21092                .ok()?;
21093            Some(())
21094        });
21095    }
21096
21097    fn on_buffer_event(
21098        &mut self,
21099        multibuffer: &Entity<MultiBuffer>,
21100        event: &multi_buffer::Event,
21101        window: &mut Window,
21102        cx: &mut Context<Self>,
21103    ) {
21104        match event {
21105            multi_buffer::Event::Edited { edited_buffer } => {
21106                self.scrollbar_marker_state.dirty = true;
21107                self.active_indent_guides_state.dirty = true;
21108                self.refresh_active_diagnostics(cx);
21109                self.refresh_code_actions(window, cx);
21110                self.refresh_selected_text_highlights(true, window, cx);
21111                self.refresh_single_line_folds(window, cx);
21112                self.refresh_matching_bracket_highlights(window, cx);
21113                if self.has_active_edit_prediction() {
21114                    self.update_visible_edit_prediction(window, cx);
21115                }
21116
21117                if let Some(buffer) = edited_buffer {
21118                    if buffer.read(cx).file().is_none() {
21119                        cx.emit(EditorEvent::TitleChanged);
21120                    }
21121
21122                    if self.project.is_some() {
21123                        let buffer_id = buffer.read(cx).remote_id();
21124                        self.register_buffer(buffer_id, cx);
21125                        self.update_lsp_data(Some(buffer_id), window, cx);
21126                        self.refresh_inlay_hints(
21127                            InlayHintRefreshReason::BufferEdited(buffer_id),
21128                            cx,
21129                        );
21130                    }
21131                }
21132
21133                cx.emit(EditorEvent::BufferEdited);
21134                cx.emit(SearchEvent::MatchesInvalidated);
21135
21136                let Some(project) = &self.project else { return };
21137                let (telemetry, is_via_ssh) = {
21138                    let project = project.read(cx);
21139                    let telemetry = project.client().telemetry().clone();
21140                    let is_via_ssh = project.is_via_remote_server();
21141                    (telemetry, is_via_ssh)
21142                };
21143                telemetry.log_edit_event("editor", is_via_ssh);
21144            }
21145            multi_buffer::Event::ExcerptsAdded {
21146                buffer,
21147                predecessor,
21148                excerpts,
21149            } => {
21150                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21151                let buffer_id = buffer.read(cx).remote_id();
21152                if self.buffer.read(cx).diff_for(buffer_id).is_none()
21153                    && let Some(project) = &self.project
21154                {
21155                    update_uncommitted_diff_for_buffer(
21156                        cx.entity(),
21157                        project,
21158                        [buffer.clone()],
21159                        self.buffer.clone(),
21160                        cx,
21161                    )
21162                    .detach();
21163                }
21164                self.update_lsp_data(Some(buffer_id), window, cx);
21165                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
21166                cx.emit(EditorEvent::ExcerptsAdded {
21167                    buffer: buffer.clone(),
21168                    predecessor: *predecessor,
21169                    excerpts: excerpts.clone(),
21170                });
21171            }
21172            multi_buffer::Event::ExcerptsRemoved {
21173                ids,
21174                removed_buffer_ids,
21175            } => {
21176                if let Some(inlay_hints) = &mut self.inlay_hints {
21177                    inlay_hints.remove_inlay_chunk_data(removed_buffer_ids);
21178                }
21179                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
21180                for buffer_id in removed_buffer_ids {
21181                    self.registered_buffers.remove(buffer_id);
21182                }
21183                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
21184                cx.emit(EditorEvent::ExcerptsRemoved {
21185                    ids: ids.clone(),
21186                    removed_buffer_ids: removed_buffer_ids.clone(),
21187                });
21188            }
21189            multi_buffer::Event::ExcerptsEdited {
21190                excerpt_ids,
21191                buffer_ids,
21192            } => {
21193                self.display_map.update(cx, |map, cx| {
21194                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
21195                });
21196                cx.emit(EditorEvent::ExcerptsEdited {
21197                    ids: excerpt_ids.clone(),
21198                });
21199            }
21200            multi_buffer::Event::ExcerptsExpanded { ids } => {
21201                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
21202                self.refresh_document_highlights(cx);
21203                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
21204            }
21205            multi_buffer::Event::Reparsed(buffer_id) => {
21206                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21207                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
21208
21209                cx.emit(EditorEvent::Reparsed(*buffer_id));
21210            }
21211            multi_buffer::Event::DiffHunksToggled => {
21212                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21213            }
21214            multi_buffer::Event::LanguageChanged(buffer_id) => {
21215                self.registered_buffers.remove(&buffer_id);
21216                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
21217                cx.emit(EditorEvent::Reparsed(*buffer_id));
21218                cx.notify();
21219            }
21220            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
21221            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
21222            multi_buffer::Event::FileHandleChanged
21223            | multi_buffer::Event::Reloaded
21224            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
21225            multi_buffer::Event::DiagnosticsUpdated => {
21226                self.update_diagnostics_state(window, cx);
21227            }
21228            _ => {}
21229        };
21230    }
21231
21232    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
21233        if !self.diagnostics_enabled() {
21234            return;
21235        }
21236        self.refresh_active_diagnostics(cx);
21237        self.refresh_inline_diagnostics(true, window, cx);
21238        self.scrollbar_marker_state.dirty = true;
21239        cx.notify();
21240    }
21241
21242    pub fn start_temporary_diff_override(&mut self) {
21243        self.load_diff_task.take();
21244        self.temporary_diff_override = true;
21245    }
21246
21247    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
21248        self.temporary_diff_override = false;
21249        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
21250        self.buffer.update(cx, |buffer, cx| {
21251            buffer.set_all_diff_hunks_collapsed(cx);
21252        });
21253
21254        if let Some(project) = self.project.clone() {
21255            self.load_diff_task = Some(
21256                update_uncommitted_diff_for_buffer(
21257                    cx.entity(),
21258                    &project,
21259                    self.buffer.read(cx).all_buffers(),
21260                    self.buffer.clone(),
21261                    cx,
21262                )
21263                .shared(),
21264            );
21265        }
21266    }
21267
21268    fn on_display_map_changed(
21269        &mut self,
21270        _: Entity<DisplayMap>,
21271        _: &mut Window,
21272        cx: &mut Context<Self>,
21273    ) {
21274        cx.notify();
21275    }
21276
21277    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21278        if self.diagnostics_enabled() {
21279            let new_severity = EditorSettings::get_global(cx)
21280                .diagnostics_max_severity
21281                .unwrap_or(DiagnosticSeverity::Hint);
21282            self.set_max_diagnostics_severity(new_severity, cx);
21283        }
21284        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21285        self.update_edit_prediction_settings(cx);
21286        self.refresh_edit_prediction(true, false, window, cx);
21287        self.refresh_inline_values(cx);
21288        self.refresh_inlay_hints(
21289            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
21290                self.selections.newest_anchor().head(),
21291                &self.buffer.read(cx).snapshot(cx),
21292                cx,
21293            )),
21294            cx,
21295        );
21296
21297        let old_cursor_shape = self.cursor_shape;
21298        let old_show_breadcrumbs = self.show_breadcrumbs;
21299
21300        {
21301            let editor_settings = EditorSettings::get_global(cx);
21302            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
21303            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
21304            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
21305            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
21306        }
21307
21308        if old_cursor_shape != self.cursor_shape {
21309            cx.emit(EditorEvent::CursorShapeChanged);
21310        }
21311
21312        if old_show_breadcrumbs != self.show_breadcrumbs {
21313            cx.emit(EditorEvent::BreadcrumbsChanged);
21314        }
21315
21316        let project_settings = ProjectSettings::get_global(cx);
21317        self.buffer_serialization = self
21318            .should_serialize_buffer()
21319            .then(|| BufferSerialization::new(project_settings.session.restore_unsaved_buffers));
21320
21321        if self.mode.is_full() {
21322            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
21323            let inline_blame_enabled = project_settings.git.inline_blame.enabled;
21324            if self.show_inline_diagnostics != show_inline_diagnostics {
21325                self.show_inline_diagnostics = show_inline_diagnostics;
21326                self.refresh_inline_diagnostics(false, window, cx);
21327            }
21328
21329            if self.git_blame_inline_enabled != inline_blame_enabled {
21330                self.toggle_git_blame_inline_internal(false, window, cx);
21331            }
21332
21333            let minimap_settings = EditorSettings::get_global(cx).minimap;
21334            if self.minimap_visibility != MinimapVisibility::Disabled {
21335                if self.minimap_visibility.settings_visibility()
21336                    != minimap_settings.minimap_enabled()
21337                {
21338                    self.set_minimap_visibility(
21339                        MinimapVisibility::for_mode(self.mode(), cx),
21340                        window,
21341                        cx,
21342                    );
21343                } else if let Some(minimap_entity) = self.minimap.as_ref() {
21344                    minimap_entity.update(cx, |minimap_editor, cx| {
21345                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
21346                    })
21347                }
21348            }
21349        }
21350
21351        if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
21352            colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
21353        }) {
21354            if !inlay_splice.is_empty() {
21355                self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
21356            }
21357            self.refresh_colors_for_visible_range(None, window, cx);
21358        }
21359
21360        cx.notify();
21361    }
21362
21363    pub fn set_searchable(&mut self, searchable: bool) {
21364        self.searchable = searchable;
21365    }
21366
21367    pub fn searchable(&self) -> bool {
21368        self.searchable
21369    }
21370
21371    pub fn open_excerpts_in_split(
21372        &mut self,
21373        _: &OpenExcerptsSplit,
21374        window: &mut Window,
21375        cx: &mut Context<Self>,
21376    ) {
21377        self.open_excerpts_common(None, true, window, cx)
21378    }
21379
21380    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
21381        self.open_excerpts_common(None, false, window, cx)
21382    }
21383
21384    fn open_excerpts_common(
21385        &mut self,
21386        jump_data: Option<JumpData>,
21387        split: bool,
21388        window: &mut Window,
21389        cx: &mut Context<Self>,
21390    ) {
21391        let Some(workspace) = self.workspace() else {
21392            cx.propagate();
21393            return;
21394        };
21395
21396        if self.buffer.read(cx).is_singleton() {
21397            cx.propagate();
21398            return;
21399        }
21400
21401        let mut new_selections_by_buffer = HashMap::default();
21402        match &jump_data {
21403            Some(JumpData::MultiBufferPoint {
21404                excerpt_id,
21405                position,
21406                anchor,
21407                line_offset_from_top,
21408            }) => {
21409                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
21410                if let Some(buffer) = multi_buffer_snapshot
21411                    .buffer_id_for_excerpt(*excerpt_id)
21412                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
21413                {
21414                    let buffer_snapshot = buffer.read(cx).snapshot();
21415                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
21416                        language::ToPoint::to_point(anchor, &buffer_snapshot)
21417                    } else {
21418                        buffer_snapshot.clip_point(*position, Bias::Left)
21419                    };
21420                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
21421                    new_selections_by_buffer.insert(
21422                        buffer,
21423                        (
21424                            vec![jump_to_offset..jump_to_offset],
21425                            Some(*line_offset_from_top),
21426                        ),
21427                    );
21428                }
21429            }
21430            Some(JumpData::MultiBufferRow {
21431                row,
21432                line_offset_from_top,
21433            }) => {
21434                let point = MultiBufferPoint::new(row.0, 0);
21435                if let Some((buffer, buffer_point, _)) =
21436                    self.buffer.read(cx).point_to_buffer_point(point, cx)
21437                {
21438                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
21439                    new_selections_by_buffer
21440                        .entry(buffer)
21441                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
21442                        .0
21443                        .push(buffer_offset..buffer_offset)
21444                }
21445            }
21446            None => {
21447                let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
21448                let multi_buffer = self.buffer.read(cx);
21449                for selection in selections {
21450                    for (snapshot, range, _, anchor) in multi_buffer
21451                        .snapshot(cx)
21452                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
21453                    {
21454                        if let Some(anchor) = anchor {
21455                            let Some(buffer_handle) = multi_buffer.buffer_for_anchor(anchor, cx)
21456                            else {
21457                                continue;
21458                            };
21459                            let offset = text::ToOffset::to_offset(
21460                                &anchor.text_anchor,
21461                                &buffer_handle.read(cx).snapshot(),
21462                            );
21463                            let range = offset..offset;
21464                            new_selections_by_buffer
21465                                .entry(buffer_handle)
21466                                .or_insert((Vec::new(), None))
21467                                .0
21468                                .push(range)
21469                        } else {
21470                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
21471                            else {
21472                                continue;
21473                            };
21474                            new_selections_by_buffer
21475                                .entry(buffer_handle)
21476                                .or_insert((Vec::new(), None))
21477                                .0
21478                                .push(range)
21479                        }
21480                    }
21481                }
21482            }
21483        }
21484
21485        new_selections_by_buffer
21486            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
21487
21488        if new_selections_by_buffer.is_empty() {
21489            return;
21490        }
21491
21492        // We defer the pane interaction because we ourselves are a workspace item
21493        // and activating a new item causes the pane to call a method on us reentrantly,
21494        // which panics if we're on the stack.
21495        window.defer(cx, move |window, cx| {
21496            workspace.update(cx, |workspace, cx| {
21497                let pane = if split {
21498                    workspace.adjacent_pane(window, cx)
21499                } else {
21500                    workspace.active_pane().clone()
21501                };
21502
21503                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
21504                    let editor = buffer
21505                        .read(cx)
21506                        .file()
21507                        .is_none()
21508                        .then(|| {
21509                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
21510                            // so `workspace.open_project_item` will never find them, always opening a new editor.
21511                            // Instead, we try to activate the existing editor in the pane first.
21512                            let (editor, pane_item_index) =
21513                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
21514                                    let editor = item.downcast::<Editor>()?;
21515                                    let singleton_buffer =
21516                                        editor.read(cx).buffer().read(cx).as_singleton()?;
21517                                    if singleton_buffer == buffer {
21518                                        Some((editor, i))
21519                                    } else {
21520                                        None
21521                                    }
21522                                })?;
21523                            pane.update(cx, |pane, cx| {
21524                                pane.activate_item(pane_item_index, true, true, window, cx)
21525                            });
21526                            Some(editor)
21527                        })
21528                        .flatten()
21529                        .unwrap_or_else(|| {
21530                            workspace.open_project_item::<Self>(
21531                                pane.clone(),
21532                                buffer,
21533                                true,
21534                                true,
21535                                window,
21536                                cx,
21537                            )
21538                        });
21539
21540                    editor.update(cx, |editor, cx| {
21541                        let autoscroll = match scroll_offset {
21542                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
21543                            None => Autoscroll::newest(),
21544                        };
21545                        let nav_history = editor.nav_history.take();
21546                        editor.change_selections(
21547                            SelectionEffects::scroll(autoscroll),
21548                            window,
21549                            cx,
21550                            |s| {
21551                                s.select_ranges(ranges);
21552                            },
21553                        );
21554                        editor.nav_history = nav_history;
21555                    });
21556                }
21557            })
21558        });
21559    }
21560
21561    // For now, don't allow opening excerpts in buffers that aren't backed by
21562    // regular project files.
21563    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
21564        file.is_none_or(|file| project::File::from_dyn(Some(file)).is_some())
21565    }
21566
21567    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
21568        let snapshot = self.buffer.read(cx).read(cx);
21569        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
21570        Some(
21571            ranges
21572                .iter()
21573                .map(move |range| {
21574                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
21575                })
21576                .collect(),
21577        )
21578    }
21579
21580    fn selection_replacement_ranges(
21581        &self,
21582        range: Range<OffsetUtf16>,
21583        cx: &mut App,
21584    ) -> Vec<Range<OffsetUtf16>> {
21585        let selections = self
21586            .selections
21587            .all::<OffsetUtf16>(&self.display_snapshot(cx));
21588        let newest_selection = selections
21589            .iter()
21590            .max_by_key(|selection| selection.id)
21591            .unwrap();
21592        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
21593        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
21594        let snapshot = self.buffer.read(cx).read(cx);
21595        selections
21596            .into_iter()
21597            .map(|mut selection| {
21598                selection.start.0 =
21599                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
21600                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
21601                snapshot.clip_offset_utf16(selection.start, Bias::Left)
21602                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
21603            })
21604            .collect()
21605    }
21606
21607    fn report_editor_event(
21608        &self,
21609        reported_event: ReportEditorEvent,
21610        file_extension: Option<String>,
21611        cx: &App,
21612    ) {
21613        if cfg!(any(test, feature = "test-support")) {
21614            return;
21615        }
21616
21617        let Some(project) = &self.project else { return };
21618
21619        // If None, we are in a file without an extension
21620        let file = self
21621            .buffer
21622            .read(cx)
21623            .as_singleton()
21624            .and_then(|b| b.read(cx).file());
21625        let file_extension = file_extension.or(file
21626            .as_ref()
21627            .and_then(|file| Path::new(file.file_name(cx)).extension())
21628            .and_then(|e| e.to_str())
21629            .map(|a| a.to_string()));
21630
21631        let vim_mode = vim_flavor(cx).is_some();
21632
21633        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
21634        let copilot_enabled = edit_predictions_provider
21635            == language::language_settings::EditPredictionProvider::Copilot;
21636        let copilot_enabled_for_language = self
21637            .buffer
21638            .read(cx)
21639            .language_settings(cx)
21640            .show_edit_predictions;
21641
21642        let project = project.read(cx);
21643        let event_type = reported_event.event_type();
21644
21645        if let ReportEditorEvent::Saved { auto_saved } = reported_event {
21646            telemetry::event!(
21647                event_type,
21648                type = if auto_saved {"autosave"} else {"manual"},
21649                file_extension,
21650                vim_mode,
21651                copilot_enabled,
21652                copilot_enabled_for_language,
21653                edit_predictions_provider,
21654                is_via_ssh = project.is_via_remote_server(),
21655            );
21656        } else {
21657            telemetry::event!(
21658                event_type,
21659                file_extension,
21660                vim_mode,
21661                copilot_enabled,
21662                copilot_enabled_for_language,
21663                edit_predictions_provider,
21664                is_via_ssh = project.is_via_remote_server(),
21665            );
21666        };
21667    }
21668
21669    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
21670    /// with each line being an array of {text, highlight} objects.
21671    fn copy_highlight_json(
21672        &mut self,
21673        _: &CopyHighlightJson,
21674        window: &mut Window,
21675        cx: &mut Context<Self>,
21676    ) {
21677        #[derive(Serialize)]
21678        struct Chunk<'a> {
21679            text: String,
21680            highlight: Option<&'a str>,
21681        }
21682
21683        let snapshot = self.buffer.read(cx).snapshot(cx);
21684        let range = self
21685            .selected_text_range(false, window, cx)
21686            .and_then(|selection| {
21687                if selection.range.is_empty() {
21688                    None
21689                } else {
21690                    Some(
21691                        snapshot.offset_utf16_to_offset(OffsetUtf16(selection.range.start))
21692                            ..snapshot.offset_utf16_to_offset(OffsetUtf16(selection.range.end)),
21693                    )
21694                }
21695            })
21696            .unwrap_or_else(|| 0..snapshot.len());
21697
21698        let chunks = snapshot.chunks(range, true);
21699        let mut lines = Vec::new();
21700        let mut line: VecDeque<Chunk> = VecDeque::new();
21701
21702        let Some(style) = self.style.as_ref() else {
21703            return;
21704        };
21705
21706        for chunk in chunks {
21707            let highlight = chunk
21708                .syntax_highlight_id
21709                .and_then(|id| id.name(&style.syntax));
21710            let mut chunk_lines = chunk.text.split('\n').peekable();
21711            while let Some(text) = chunk_lines.next() {
21712                let mut merged_with_last_token = false;
21713                if let Some(last_token) = line.back_mut()
21714                    && last_token.highlight == highlight
21715                {
21716                    last_token.text.push_str(text);
21717                    merged_with_last_token = true;
21718                }
21719
21720                if !merged_with_last_token {
21721                    line.push_back(Chunk {
21722                        text: text.into(),
21723                        highlight,
21724                    });
21725                }
21726
21727                if chunk_lines.peek().is_some() {
21728                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
21729                        line.pop_front();
21730                    }
21731                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
21732                        line.pop_back();
21733                    }
21734
21735                    lines.push(mem::take(&mut line));
21736                }
21737            }
21738        }
21739
21740        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
21741            return;
21742        };
21743        cx.write_to_clipboard(ClipboardItem::new_string(lines));
21744    }
21745
21746    pub fn open_context_menu(
21747        &mut self,
21748        _: &OpenContextMenu,
21749        window: &mut Window,
21750        cx: &mut Context<Self>,
21751    ) {
21752        self.request_autoscroll(Autoscroll::newest(), cx);
21753        let position = self
21754            .selections
21755            .newest_display(&self.display_snapshot(cx))
21756            .start;
21757        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
21758    }
21759
21760    pub fn replay_insert_event(
21761        &mut self,
21762        text: &str,
21763        relative_utf16_range: Option<Range<isize>>,
21764        window: &mut Window,
21765        cx: &mut Context<Self>,
21766    ) {
21767        if !self.input_enabled {
21768            cx.emit(EditorEvent::InputIgnored { text: text.into() });
21769            return;
21770        }
21771        if let Some(relative_utf16_range) = relative_utf16_range {
21772            let selections = self
21773                .selections
21774                .all::<OffsetUtf16>(&self.display_snapshot(cx));
21775            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21776                let new_ranges = selections.into_iter().map(|range| {
21777                    let start = OffsetUtf16(
21778                        range
21779                            .head()
21780                            .0
21781                            .saturating_add_signed(relative_utf16_range.start),
21782                    );
21783                    let end = OffsetUtf16(
21784                        range
21785                            .head()
21786                            .0
21787                            .saturating_add_signed(relative_utf16_range.end),
21788                    );
21789                    start..end
21790                });
21791                s.select_ranges(new_ranges);
21792            });
21793        }
21794
21795        self.handle_input(text, window, cx);
21796    }
21797
21798    pub fn is_focused(&self, window: &Window) -> bool {
21799        self.focus_handle.is_focused(window)
21800    }
21801
21802    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21803        cx.emit(EditorEvent::Focused);
21804
21805        if let Some(descendant) = self
21806            .last_focused_descendant
21807            .take()
21808            .and_then(|descendant| descendant.upgrade())
21809        {
21810            window.focus(&descendant);
21811        } else {
21812            if let Some(blame) = self.blame.as_ref() {
21813                blame.update(cx, GitBlame::focus)
21814            }
21815
21816            self.blink_manager.update(cx, BlinkManager::enable);
21817            self.show_cursor_names(window, cx);
21818            self.buffer.update(cx, |buffer, cx| {
21819                buffer.finalize_last_transaction(cx);
21820                if self.leader_id.is_none() {
21821                    buffer.set_active_selections(
21822                        &self.selections.disjoint_anchors_arc(),
21823                        self.selections.line_mode(),
21824                        self.cursor_shape,
21825                        cx,
21826                    );
21827                }
21828            });
21829        }
21830    }
21831
21832    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
21833        cx.emit(EditorEvent::FocusedIn)
21834    }
21835
21836    fn handle_focus_out(
21837        &mut self,
21838        event: FocusOutEvent,
21839        _window: &mut Window,
21840        cx: &mut Context<Self>,
21841    ) {
21842        if event.blurred != self.focus_handle {
21843            self.last_focused_descendant = Some(event.blurred);
21844        }
21845        self.selection_drag_state = SelectionDragState::None;
21846        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
21847    }
21848
21849    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21850        self.blink_manager.update(cx, BlinkManager::disable);
21851        self.buffer
21852            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
21853
21854        if let Some(blame) = self.blame.as_ref() {
21855            blame.update(cx, GitBlame::blur)
21856        }
21857        if !self.hover_state.focused(window, cx) {
21858            hide_hover(self, cx);
21859        }
21860        if !self
21861            .context_menu
21862            .borrow()
21863            .as_ref()
21864            .is_some_and(|context_menu| context_menu.focused(window, cx))
21865        {
21866            self.hide_context_menu(window, cx);
21867        }
21868        self.take_active_edit_prediction(cx);
21869        cx.emit(EditorEvent::Blurred);
21870        cx.notify();
21871    }
21872
21873    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21874        let mut pending: String = window
21875            .pending_input_keystrokes()
21876            .into_iter()
21877            .flatten()
21878            .filter_map(|keystroke| {
21879                if keystroke.modifiers.is_subset_of(&Modifiers::shift()) {
21880                    keystroke.key_char.clone()
21881                } else {
21882                    None
21883                }
21884            })
21885            .collect();
21886
21887        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
21888            pending = "".to_string();
21889        }
21890
21891        let existing_pending = self
21892            .text_highlights::<PendingInput>(cx)
21893            .map(|(_, ranges)| ranges.to_vec());
21894        if existing_pending.is_none() && pending.is_empty() {
21895            return;
21896        }
21897        let transaction =
21898            self.transact(window, cx, |this, window, cx| {
21899                let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
21900                let edits = selections
21901                    .iter()
21902                    .map(|selection| (selection.end..selection.end, pending.clone()));
21903                this.edit(edits, cx);
21904                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21905                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
21906                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
21907                    }));
21908                });
21909                if let Some(existing_ranges) = existing_pending {
21910                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
21911                    this.edit(edits, cx);
21912                }
21913            });
21914
21915        let snapshot = self.snapshot(window, cx);
21916        let ranges = self
21917            .selections
21918            .all::<usize>(&snapshot.display_snapshot)
21919            .into_iter()
21920            .map(|selection| {
21921                snapshot.buffer_snapshot().anchor_after(selection.end)
21922                    ..snapshot
21923                        .buffer_snapshot()
21924                        .anchor_before(selection.end + pending.len())
21925            })
21926            .collect();
21927
21928        if pending.is_empty() {
21929            self.clear_highlights::<PendingInput>(cx);
21930        } else {
21931            self.highlight_text::<PendingInput>(
21932                ranges,
21933                HighlightStyle {
21934                    underline: Some(UnderlineStyle {
21935                        thickness: px(1.),
21936                        color: None,
21937                        wavy: false,
21938                    }),
21939                    ..Default::default()
21940                },
21941                cx,
21942            );
21943        }
21944
21945        self.ime_transaction = self.ime_transaction.or(transaction);
21946        if let Some(transaction) = self.ime_transaction {
21947            self.buffer.update(cx, |buffer, cx| {
21948                buffer.group_until_transaction(transaction, cx);
21949            });
21950        }
21951
21952        if self.text_highlights::<PendingInput>(cx).is_none() {
21953            self.ime_transaction.take();
21954        }
21955    }
21956
21957    pub fn register_action_renderer(
21958        &mut self,
21959        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
21960    ) -> Subscription {
21961        let id = self.next_editor_action_id.post_inc();
21962        self.editor_actions
21963            .borrow_mut()
21964            .insert(id, Box::new(listener));
21965
21966        let editor_actions = self.editor_actions.clone();
21967        Subscription::new(move || {
21968            editor_actions.borrow_mut().remove(&id);
21969        })
21970    }
21971
21972    pub fn register_action<A: Action>(
21973        &mut self,
21974        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
21975    ) -> Subscription {
21976        let id = self.next_editor_action_id.post_inc();
21977        let listener = Arc::new(listener);
21978        self.editor_actions.borrow_mut().insert(
21979            id,
21980            Box::new(move |_, window, _| {
21981                let listener = listener.clone();
21982                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
21983                    let action = action.downcast_ref().unwrap();
21984                    if phase == DispatchPhase::Bubble {
21985                        listener(action, window, cx)
21986                    }
21987                })
21988            }),
21989        );
21990
21991        let editor_actions = self.editor_actions.clone();
21992        Subscription::new(move || {
21993            editor_actions.borrow_mut().remove(&id);
21994        })
21995    }
21996
21997    pub fn file_header_size(&self) -> u32 {
21998        FILE_HEADER_HEIGHT
21999    }
22000
22001    pub fn restore(
22002        &mut self,
22003        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
22004        window: &mut Window,
22005        cx: &mut Context<Self>,
22006    ) {
22007        let workspace = self.workspace();
22008        let project = self.project();
22009        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
22010            let mut tasks = Vec::new();
22011            for (buffer_id, changes) in revert_changes {
22012                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
22013                    buffer.update(cx, |buffer, cx| {
22014                        buffer.edit(
22015                            changes
22016                                .into_iter()
22017                                .map(|(range, text)| (range, text.to_string())),
22018                            None,
22019                            cx,
22020                        );
22021                    });
22022
22023                    if let Some(project) =
22024                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
22025                    {
22026                        project.update(cx, |project, cx| {
22027                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
22028                        })
22029                    }
22030                }
22031            }
22032            tasks
22033        });
22034        cx.spawn_in(window, async move |_, cx| {
22035            for (buffer, task) in save_tasks {
22036                let result = task.await;
22037                if result.is_err() {
22038                    let Some(path) = buffer
22039                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
22040                        .ok()
22041                    else {
22042                        continue;
22043                    };
22044                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
22045                        let Some(task) = cx
22046                            .update_window_entity(workspace, |workspace, window, cx| {
22047                                workspace
22048                                    .open_path_preview(path, None, false, false, false, window, cx)
22049                            })
22050                            .ok()
22051                        else {
22052                            continue;
22053                        };
22054                        task.await.log_err();
22055                    }
22056                }
22057            }
22058        })
22059        .detach();
22060        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
22061            selections.refresh()
22062        });
22063    }
22064
22065    pub fn to_pixel_point(
22066        &self,
22067        source: multi_buffer::Anchor,
22068        editor_snapshot: &EditorSnapshot,
22069        window: &mut Window,
22070    ) -> Option<gpui::Point<Pixels>> {
22071        let source_point = source.to_display_point(editor_snapshot);
22072        self.display_to_pixel_point(source_point, editor_snapshot, window)
22073    }
22074
22075    pub fn display_to_pixel_point(
22076        &self,
22077        source: DisplayPoint,
22078        editor_snapshot: &EditorSnapshot,
22079        window: &mut Window,
22080    ) -> Option<gpui::Point<Pixels>> {
22081        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
22082        let text_layout_details = self.text_layout_details(window);
22083        let scroll_top = text_layout_details
22084            .scroll_anchor
22085            .scroll_position(editor_snapshot)
22086            .y;
22087
22088        if source.row().as_f64() < scroll_top.floor() {
22089            return None;
22090        }
22091        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
22092        let source_y = line_height * (source.row().as_f64() - scroll_top) as f32;
22093        Some(gpui::Point::new(source_x, source_y))
22094    }
22095
22096    pub fn has_visible_completions_menu(&self) -> bool {
22097        !self.edit_prediction_preview_is_active()
22098            && self.context_menu.borrow().as_ref().is_some_and(|menu| {
22099                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
22100            })
22101    }
22102
22103    pub fn register_addon<T: Addon>(&mut self, instance: T) {
22104        if self.mode.is_minimap() {
22105            return;
22106        }
22107        self.addons
22108            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
22109    }
22110
22111    pub fn unregister_addon<T: Addon>(&mut self) {
22112        self.addons.remove(&std::any::TypeId::of::<T>());
22113    }
22114
22115    pub fn addon<T: Addon>(&self) -> Option<&T> {
22116        let type_id = std::any::TypeId::of::<T>();
22117        self.addons
22118            .get(&type_id)
22119            .and_then(|item| item.to_any().downcast_ref::<T>())
22120    }
22121
22122    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
22123        let type_id = std::any::TypeId::of::<T>();
22124        self.addons
22125            .get_mut(&type_id)
22126            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
22127    }
22128
22129    fn character_dimensions(&self, window: &mut Window) -> CharacterDimensions {
22130        let text_layout_details = self.text_layout_details(window);
22131        let style = &text_layout_details.editor_style;
22132        let font_id = window.text_system().resolve_font(&style.text.font());
22133        let font_size = style.text.font_size.to_pixels(window.rem_size());
22134        let line_height = style.text.line_height_in_pixels(window.rem_size());
22135        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
22136        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
22137
22138        CharacterDimensions {
22139            em_width,
22140            em_advance,
22141            line_height,
22142        }
22143    }
22144
22145    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
22146        self.load_diff_task.clone()
22147    }
22148
22149    fn read_metadata_from_db(
22150        &mut self,
22151        item_id: u64,
22152        workspace_id: WorkspaceId,
22153        window: &mut Window,
22154        cx: &mut Context<Editor>,
22155    ) {
22156        if self.buffer_kind(cx) == ItemBufferKind::Singleton
22157            && !self.mode.is_minimap()
22158            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
22159        {
22160            let buffer_snapshot = OnceCell::new();
22161
22162            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err()
22163                && !folds.is_empty()
22164            {
22165                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
22166                self.fold_ranges(
22167                    folds
22168                        .into_iter()
22169                        .map(|(start, end)| {
22170                            snapshot.clip_offset(start, Bias::Left)
22171                                ..snapshot.clip_offset(end, Bias::Right)
22172                        })
22173                        .collect(),
22174                    false,
22175                    window,
22176                    cx,
22177                );
22178            }
22179
22180            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err()
22181                && !selections.is_empty()
22182            {
22183                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
22184                // skip adding the initial selection to selection history
22185                self.selection_history.mode = SelectionHistoryMode::Skipping;
22186                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
22187                    s.select_ranges(selections.into_iter().map(|(start, end)| {
22188                        snapshot.clip_offset(start, Bias::Left)
22189                            ..snapshot.clip_offset(end, Bias::Right)
22190                    }));
22191                });
22192                self.selection_history.mode = SelectionHistoryMode::Normal;
22193            };
22194        }
22195
22196        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
22197    }
22198
22199    fn update_lsp_data(
22200        &mut self,
22201        for_buffer: Option<BufferId>,
22202        window: &mut Window,
22203        cx: &mut Context<'_, Self>,
22204    ) {
22205        self.pull_diagnostics(for_buffer, window, cx);
22206        self.refresh_colors_for_visible_range(for_buffer, window, cx);
22207    }
22208
22209    fn register_visible_buffers(&mut self, cx: &mut Context<Self>) {
22210        if self.ignore_lsp_data() {
22211            return;
22212        }
22213        for (_, (visible_buffer, _, _)) in self.visible_excerpts(cx) {
22214            self.register_buffer(visible_buffer.read(cx).remote_id(), cx);
22215        }
22216    }
22217
22218    fn register_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
22219        if self.ignore_lsp_data() {
22220            return;
22221        }
22222
22223        if !self.registered_buffers.contains_key(&buffer_id)
22224            && let Some(project) = self.project.as_ref()
22225        {
22226            if let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) {
22227                project.update(cx, |project, cx| {
22228                    self.registered_buffers.insert(
22229                        buffer_id,
22230                        project.register_buffer_with_language_servers(&buffer, cx),
22231                    );
22232                });
22233            } else {
22234                self.registered_buffers.remove(&buffer_id);
22235            }
22236        }
22237    }
22238
22239    fn ignore_lsp_data(&self) -> bool {
22240        // `ActiveDiagnostic::All` is a special mode where editor's diagnostics are managed by the external view,
22241        // skip any LSP updates for it.
22242        self.active_diagnostics == ActiveDiagnostic::All || !self.mode().is_full()
22243    }
22244}
22245
22246fn edit_for_markdown_paste<'a>(
22247    buffer: &MultiBufferSnapshot,
22248    range: Range<usize>,
22249    to_insert: &'a str,
22250    url: Option<url::Url>,
22251) -> (Range<usize>, Cow<'a, str>) {
22252    if url.is_none() {
22253        return (range, Cow::Borrowed(to_insert));
22254    };
22255
22256    let old_text = buffer.text_for_range(range.clone()).collect::<String>();
22257
22258    let new_text = if range.is_empty() || url::Url::parse(&old_text).is_ok() {
22259        Cow::Borrowed(to_insert)
22260    } else {
22261        Cow::Owned(format!("[{old_text}]({to_insert})"))
22262    };
22263    (range, new_text)
22264}
22265
22266#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
22267pub enum VimFlavor {
22268    Vim,
22269    Helix,
22270}
22271
22272pub fn vim_flavor(cx: &App) -> Option<VimFlavor> {
22273    if vim_mode_setting::HelixModeSetting::try_get(cx)
22274        .map(|helix_mode| helix_mode.0)
22275        .unwrap_or(false)
22276    {
22277        Some(VimFlavor::Helix)
22278    } else if vim_mode_setting::VimModeSetting::try_get(cx)
22279        .map(|vim_mode| vim_mode.0)
22280        .unwrap_or(false)
22281    {
22282        Some(VimFlavor::Vim)
22283    } else {
22284        None // neither vim nor helix mode
22285    }
22286}
22287
22288fn process_completion_for_edit(
22289    completion: &Completion,
22290    intent: CompletionIntent,
22291    buffer: &Entity<Buffer>,
22292    cursor_position: &text::Anchor,
22293    cx: &mut Context<Editor>,
22294) -> CompletionEdit {
22295    let buffer = buffer.read(cx);
22296    let buffer_snapshot = buffer.snapshot();
22297    let (snippet, new_text) = if completion.is_snippet() {
22298        let mut snippet_source = completion.new_text.clone();
22299        // Workaround for typescript language server issues so that methods don't expand within
22300        // strings and functions with type expressions. The previous point is used because the query
22301        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
22302        let previous_point = text::ToPoint::to_point(cursor_position, &buffer_snapshot);
22303        let previous_point = if previous_point.column > 0 {
22304            cursor_position.to_previous_offset(&buffer_snapshot)
22305        } else {
22306            cursor_position.to_offset(&buffer_snapshot)
22307        };
22308        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point)
22309            && scope.prefers_label_for_snippet_in_completion()
22310            && let Some(label) = completion.label()
22311            && matches!(
22312                completion.kind(),
22313                Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
22314            )
22315        {
22316            snippet_source = label;
22317        }
22318        match Snippet::parse(&snippet_source).log_err() {
22319            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
22320            None => (None, completion.new_text.clone()),
22321        }
22322    } else {
22323        (None, completion.new_text.clone())
22324    };
22325
22326    let mut range_to_replace = {
22327        let replace_range = &completion.replace_range;
22328        if let CompletionSource::Lsp {
22329            insert_range: Some(insert_range),
22330            ..
22331        } = &completion.source
22332        {
22333            debug_assert_eq!(
22334                insert_range.start, replace_range.start,
22335                "insert_range and replace_range should start at the same position"
22336            );
22337            debug_assert!(
22338                insert_range
22339                    .start
22340                    .cmp(cursor_position, &buffer_snapshot)
22341                    .is_le(),
22342                "insert_range should start before or at cursor position"
22343            );
22344            debug_assert!(
22345                replace_range
22346                    .start
22347                    .cmp(cursor_position, &buffer_snapshot)
22348                    .is_le(),
22349                "replace_range should start before or at cursor position"
22350            );
22351
22352            let should_replace = match intent {
22353                CompletionIntent::CompleteWithInsert => false,
22354                CompletionIntent::CompleteWithReplace => true,
22355                CompletionIntent::Complete | CompletionIntent::Compose => {
22356                    let insert_mode =
22357                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
22358                            .completions
22359                            .lsp_insert_mode;
22360                    match insert_mode {
22361                        LspInsertMode::Insert => false,
22362                        LspInsertMode::Replace => true,
22363                        LspInsertMode::ReplaceSubsequence => {
22364                            let mut text_to_replace = buffer.chars_for_range(
22365                                buffer.anchor_before(replace_range.start)
22366                                    ..buffer.anchor_after(replace_range.end),
22367                            );
22368                            let mut current_needle = text_to_replace.next();
22369                            for haystack_ch in completion.label.text.chars() {
22370                                if let Some(needle_ch) = current_needle
22371                                    && haystack_ch.eq_ignore_ascii_case(&needle_ch)
22372                                {
22373                                    current_needle = text_to_replace.next();
22374                                }
22375                            }
22376                            current_needle.is_none()
22377                        }
22378                        LspInsertMode::ReplaceSuffix => {
22379                            if replace_range
22380                                .end
22381                                .cmp(cursor_position, &buffer_snapshot)
22382                                .is_gt()
22383                            {
22384                                let range_after_cursor = *cursor_position..replace_range.end;
22385                                let text_after_cursor = buffer
22386                                    .text_for_range(
22387                                        buffer.anchor_before(range_after_cursor.start)
22388                                            ..buffer.anchor_after(range_after_cursor.end),
22389                                    )
22390                                    .collect::<String>()
22391                                    .to_ascii_lowercase();
22392                                completion
22393                                    .label
22394                                    .text
22395                                    .to_ascii_lowercase()
22396                                    .ends_with(&text_after_cursor)
22397                            } else {
22398                                true
22399                            }
22400                        }
22401                    }
22402                }
22403            };
22404
22405            if should_replace {
22406                replace_range.clone()
22407            } else {
22408                insert_range.clone()
22409            }
22410        } else {
22411            replace_range.clone()
22412        }
22413    };
22414
22415    if range_to_replace
22416        .end
22417        .cmp(cursor_position, &buffer_snapshot)
22418        .is_lt()
22419    {
22420        range_to_replace.end = *cursor_position;
22421    }
22422
22423    CompletionEdit {
22424        new_text,
22425        replace_range: range_to_replace.to_offset(buffer),
22426        snippet,
22427    }
22428}
22429
22430struct CompletionEdit {
22431    new_text: String,
22432    replace_range: Range<usize>,
22433    snippet: Option<Snippet>,
22434}
22435
22436fn insert_extra_newline_brackets(
22437    buffer: &MultiBufferSnapshot,
22438    range: Range<usize>,
22439    language: &language::LanguageScope,
22440) -> bool {
22441    let leading_whitespace_len = buffer
22442        .reversed_chars_at(range.start)
22443        .take_while(|c| c.is_whitespace() && *c != '\n')
22444        .map(|c| c.len_utf8())
22445        .sum::<usize>();
22446    let trailing_whitespace_len = buffer
22447        .chars_at(range.end)
22448        .take_while(|c| c.is_whitespace() && *c != '\n')
22449        .map(|c| c.len_utf8())
22450        .sum::<usize>();
22451    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
22452
22453    language.brackets().any(|(pair, enabled)| {
22454        let pair_start = pair.start.trim_end();
22455        let pair_end = pair.end.trim_start();
22456
22457        enabled
22458            && pair.newline
22459            && buffer.contains_str_at(range.end, pair_end)
22460            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
22461    })
22462}
22463
22464fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
22465    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
22466        [(buffer, range, _)] => (*buffer, range.clone()),
22467        _ => return false,
22468    };
22469    let pair = {
22470        let mut result: Option<BracketMatch> = None;
22471
22472        for pair in buffer
22473            .all_bracket_ranges(range.clone())
22474            .filter(move |pair| {
22475                pair.open_range.start <= range.start && pair.close_range.end >= range.end
22476            })
22477        {
22478            let len = pair.close_range.end - pair.open_range.start;
22479
22480            if let Some(existing) = &result {
22481                let existing_len = existing.close_range.end - existing.open_range.start;
22482                if len > existing_len {
22483                    continue;
22484                }
22485            }
22486
22487            result = Some(pair);
22488        }
22489
22490        result
22491    };
22492    let Some(pair) = pair else {
22493        return false;
22494    };
22495    pair.newline_only
22496        && buffer
22497            .chars_for_range(pair.open_range.end..range.start)
22498            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
22499            .all(|c| c.is_whitespace() && c != '\n')
22500}
22501
22502fn update_uncommitted_diff_for_buffer(
22503    editor: Entity<Editor>,
22504    project: &Entity<Project>,
22505    buffers: impl IntoIterator<Item = Entity<Buffer>>,
22506    buffer: Entity<MultiBuffer>,
22507    cx: &mut App,
22508) -> Task<()> {
22509    let mut tasks = Vec::new();
22510    project.update(cx, |project, cx| {
22511        for buffer in buffers {
22512            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
22513                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
22514            }
22515        }
22516    });
22517    cx.spawn(async move |cx| {
22518        let diffs = future::join_all(tasks).await;
22519        if editor
22520            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
22521            .unwrap_or(false)
22522        {
22523            return;
22524        }
22525
22526        buffer
22527            .update(cx, |buffer, cx| {
22528                for diff in diffs.into_iter().flatten() {
22529                    buffer.add_diff(diff, cx);
22530                }
22531            })
22532            .ok();
22533    })
22534}
22535
22536fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
22537    let tab_size = tab_size.get() as usize;
22538    let mut width = offset;
22539
22540    for ch in text.chars() {
22541        width += if ch == '\t' {
22542            tab_size - (width % tab_size)
22543        } else {
22544            1
22545        };
22546    }
22547
22548    width - offset
22549}
22550
22551#[cfg(test)]
22552mod tests {
22553    use super::*;
22554
22555    #[test]
22556    fn test_string_size_with_expanded_tabs() {
22557        let nz = |val| NonZeroU32::new(val).unwrap();
22558        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
22559        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
22560        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
22561        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
22562        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
22563        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
22564        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
22565        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
22566    }
22567}
22568
22569/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
22570struct WordBreakingTokenizer<'a> {
22571    input: &'a str,
22572}
22573
22574impl<'a> WordBreakingTokenizer<'a> {
22575    fn new(input: &'a str) -> Self {
22576        Self { input }
22577    }
22578}
22579
22580fn is_char_ideographic(ch: char) -> bool {
22581    use unicode_script::Script::*;
22582    use unicode_script::UnicodeScript;
22583    matches!(ch.script(), Han | Tangut | Yi)
22584}
22585
22586fn is_grapheme_ideographic(text: &str) -> bool {
22587    text.chars().any(is_char_ideographic)
22588}
22589
22590fn is_grapheme_whitespace(text: &str) -> bool {
22591    text.chars().any(|x| x.is_whitespace())
22592}
22593
22594fn should_stay_with_preceding_ideograph(text: &str) -> bool {
22595    text.chars()
22596        .next()
22597        .is_some_and(|ch| matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…'))
22598}
22599
22600#[derive(PartialEq, Eq, Debug, Clone, Copy)]
22601enum WordBreakToken<'a> {
22602    Word { token: &'a str, grapheme_len: usize },
22603    InlineWhitespace { token: &'a str, grapheme_len: usize },
22604    Newline,
22605}
22606
22607impl<'a> Iterator for WordBreakingTokenizer<'a> {
22608    /// Yields a span, the count of graphemes in the token, and whether it was
22609    /// whitespace. Note that it also breaks at word boundaries.
22610    type Item = WordBreakToken<'a>;
22611
22612    fn next(&mut self) -> Option<Self::Item> {
22613        use unicode_segmentation::UnicodeSegmentation;
22614        if self.input.is_empty() {
22615            return None;
22616        }
22617
22618        let mut iter = self.input.graphemes(true).peekable();
22619        let mut offset = 0;
22620        let mut grapheme_len = 0;
22621        if let Some(first_grapheme) = iter.next() {
22622            let is_newline = first_grapheme == "\n";
22623            let is_whitespace = is_grapheme_whitespace(first_grapheme);
22624            offset += first_grapheme.len();
22625            grapheme_len += 1;
22626            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
22627                if let Some(grapheme) = iter.peek().copied()
22628                    && should_stay_with_preceding_ideograph(grapheme)
22629                {
22630                    offset += grapheme.len();
22631                    grapheme_len += 1;
22632                }
22633            } else {
22634                let mut words = self.input[offset..].split_word_bound_indices().peekable();
22635                let mut next_word_bound = words.peek().copied();
22636                if next_word_bound.is_some_and(|(i, _)| i == 0) {
22637                    next_word_bound = words.next();
22638                }
22639                while let Some(grapheme) = iter.peek().copied() {
22640                    if next_word_bound.is_some_and(|(i, _)| i == offset) {
22641                        break;
22642                    };
22643                    if is_grapheme_whitespace(grapheme) != is_whitespace
22644                        || (grapheme == "\n") != is_newline
22645                    {
22646                        break;
22647                    };
22648                    offset += grapheme.len();
22649                    grapheme_len += 1;
22650                    iter.next();
22651                }
22652            }
22653            let token = &self.input[..offset];
22654            self.input = &self.input[offset..];
22655            if token == "\n" {
22656                Some(WordBreakToken::Newline)
22657            } else if is_whitespace {
22658                Some(WordBreakToken::InlineWhitespace {
22659                    token,
22660                    grapheme_len,
22661                })
22662            } else {
22663                Some(WordBreakToken::Word {
22664                    token,
22665                    grapheme_len,
22666                })
22667            }
22668        } else {
22669            None
22670        }
22671    }
22672}
22673
22674#[test]
22675fn test_word_breaking_tokenizer() {
22676    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
22677        ("", &[]),
22678        ("  ", &[whitespace("  ", 2)]),
22679        ("Ʒ", &[word("Ʒ", 1)]),
22680        ("Ǽ", &[word("Ǽ", 1)]),
22681        ("", &[word("", 1)]),
22682        ("⋑⋑", &[word("⋑⋑", 2)]),
22683        (
22684            "原理,进而",
22685            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
22686        ),
22687        (
22688            "hello world",
22689            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
22690        ),
22691        (
22692            "hello, world",
22693            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
22694        ),
22695        (
22696            "  hello world",
22697            &[
22698                whitespace("  ", 2),
22699                word("hello", 5),
22700                whitespace(" ", 1),
22701                word("world", 5),
22702            ],
22703        ),
22704        (
22705            "这是什么 \n 钢笔",
22706            &[
22707                word("", 1),
22708                word("", 1),
22709                word("", 1),
22710                word("", 1),
22711                whitespace(" ", 1),
22712                newline(),
22713                whitespace(" ", 1),
22714                word("", 1),
22715                word("", 1),
22716            ],
22717        ),
22718        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
22719    ];
22720
22721    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
22722        WordBreakToken::Word {
22723            token,
22724            grapheme_len,
22725        }
22726    }
22727
22728    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
22729        WordBreakToken::InlineWhitespace {
22730            token,
22731            grapheme_len,
22732        }
22733    }
22734
22735    fn newline() -> WordBreakToken<'static> {
22736        WordBreakToken::Newline
22737    }
22738
22739    for (input, result) in tests {
22740        assert_eq!(
22741            WordBreakingTokenizer::new(input)
22742                .collect::<Vec<_>>()
22743                .as_slice(),
22744            *result,
22745        );
22746    }
22747}
22748
22749fn wrap_with_prefix(
22750    first_line_prefix: String,
22751    subsequent_lines_prefix: String,
22752    unwrapped_text: String,
22753    wrap_column: usize,
22754    tab_size: NonZeroU32,
22755    preserve_existing_whitespace: bool,
22756) -> String {
22757    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
22758    let subsequent_lines_prefix_len =
22759        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
22760    let mut wrapped_text = String::new();
22761    let mut current_line = first_line_prefix;
22762    let mut is_first_line = true;
22763
22764    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
22765    let mut current_line_len = first_line_prefix_len;
22766    let mut in_whitespace = false;
22767    for token in tokenizer {
22768        let have_preceding_whitespace = in_whitespace;
22769        match token {
22770            WordBreakToken::Word {
22771                token,
22772                grapheme_len,
22773            } => {
22774                in_whitespace = false;
22775                let current_prefix_len = if is_first_line {
22776                    first_line_prefix_len
22777                } else {
22778                    subsequent_lines_prefix_len
22779                };
22780                if current_line_len + grapheme_len > wrap_column
22781                    && current_line_len != current_prefix_len
22782                {
22783                    wrapped_text.push_str(current_line.trim_end());
22784                    wrapped_text.push('\n');
22785                    is_first_line = false;
22786                    current_line = subsequent_lines_prefix.clone();
22787                    current_line_len = subsequent_lines_prefix_len;
22788                }
22789                current_line.push_str(token);
22790                current_line_len += grapheme_len;
22791            }
22792            WordBreakToken::InlineWhitespace {
22793                mut token,
22794                mut grapheme_len,
22795            } => {
22796                in_whitespace = true;
22797                if have_preceding_whitespace && !preserve_existing_whitespace {
22798                    continue;
22799                }
22800                if !preserve_existing_whitespace {
22801                    // Keep a single whitespace grapheme as-is
22802                    if let Some(first) =
22803                        unicode_segmentation::UnicodeSegmentation::graphemes(token, true).next()
22804                    {
22805                        token = first;
22806                    } else {
22807                        token = " ";
22808                    }
22809                    grapheme_len = 1;
22810                }
22811                let current_prefix_len = if is_first_line {
22812                    first_line_prefix_len
22813                } else {
22814                    subsequent_lines_prefix_len
22815                };
22816                if current_line_len + grapheme_len > wrap_column {
22817                    wrapped_text.push_str(current_line.trim_end());
22818                    wrapped_text.push('\n');
22819                    is_first_line = false;
22820                    current_line = subsequent_lines_prefix.clone();
22821                    current_line_len = subsequent_lines_prefix_len;
22822                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
22823                    current_line.push_str(token);
22824                    current_line_len += grapheme_len;
22825                }
22826            }
22827            WordBreakToken::Newline => {
22828                in_whitespace = true;
22829                let current_prefix_len = if is_first_line {
22830                    first_line_prefix_len
22831                } else {
22832                    subsequent_lines_prefix_len
22833                };
22834                if preserve_existing_whitespace {
22835                    wrapped_text.push_str(current_line.trim_end());
22836                    wrapped_text.push('\n');
22837                    is_first_line = false;
22838                    current_line = subsequent_lines_prefix.clone();
22839                    current_line_len = subsequent_lines_prefix_len;
22840                } else if have_preceding_whitespace {
22841                    continue;
22842                } else if current_line_len + 1 > wrap_column
22843                    && current_line_len != current_prefix_len
22844                {
22845                    wrapped_text.push_str(current_line.trim_end());
22846                    wrapped_text.push('\n');
22847                    is_first_line = false;
22848                    current_line = subsequent_lines_prefix.clone();
22849                    current_line_len = subsequent_lines_prefix_len;
22850                } else if current_line_len != current_prefix_len {
22851                    current_line.push(' ');
22852                    current_line_len += 1;
22853                }
22854            }
22855        }
22856    }
22857
22858    if !current_line.is_empty() {
22859        wrapped_text.push_str(&current_line);
22860    }
22861    wrapped_text
22862}
22863
22864#[test]
22865fn test_wrap_with_prefix() {
22866    assert_eq!(
22867        wrap_with_prefix(
22868            "# ".to_string(),
22869            "# ".to_string(),
22870            "abcdefg".to_string(),
22871            4,
22872            NonZeroU32::new(4).unwrap(),
22873            false,
22874        ),
22875        "# abcdefg"
22876    );
22877    assert_eq!(
22878        wrap_with_prefix(
22879            "".to_string(),
22880            "".to_string(),
22881            "\thello world".to_string(),
22882            8,
22883            NonZeroU32::new(4).unwrap(),
22884            false,
22885        ),
22886        "hello\nworld"
22887    );
22888    assert_eq!(
22889        wrap_with_prefix(
22890            "// ".to_string(),
22891            "// ".to_string(),
22892            "xx \nyy zz aa bb cc".to_string(),
22893            12,
22894            NonZeroU32::new(4).unwrap(),
22895            false,
22896        ),
22897        "// xx yy zz\n// aa bb cc"
22898    );
22899    assert_eq!(
22900        wrap_with_prefix(
22901            String::new(),
22902            String::new(),
22903            "这是什么 \n 钢笔".to_string(),
22904            3,
22905            NonZeroU32::new(4).unwrap(),
22906            false,
22907        ),
22908        "这是什\n么 钢\n"
22909    );
22910    assert_eq!(
22911        wrap_with_prefix(
22912            String::new(),
22913            String::new(),
22914            format!("foo{}bar", '\u{2009}'), // thin space
22915            80,
22916            NonZeroU32::new(4).unwrap(),
22917            false,
22918        ),
22919        format!("foo{}bar", '\u{2009}')
22920    );
22921}
22922
22923pub trait CollaborationHub {
22924    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
22925    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
22926    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
22927}
22928
22929impl CollaborationHub for Entity<Project> {
22930    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
22931        self.read(cx).collaborators()
22932    }
22933
22934    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
22935        self.read(cx).user_store().read(cx).participant_indices()
22936    }
22937
22938    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
22939        let this = self.read(cx);
22940        let user_ids = this.collaborators().values().map(|c| c.user_id);
22941        this.user_store().read(cx).participant_names(user_ids, cx)
22942    }
22943}
22944
22945pub trait SemanticsProvider {
22946    fn hover(
22947        &self,
22948        buffer: &Entity<Buffer>,
22949        position: text::Anchor,
22950        cx: &mut App,
22951    ) -> Option<Task<Option<Vec<project::Hover>>>>;
22952
22953    fn inline_values(
22954        &self,
22955        buffer_handle: Entity<Buffer>,
22956        range: Range<text::Anchor>,
22957        cx: &mut App,
22958    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
22959
22960    fn applicable_inlay_chunks(
22961        &self,
22962        buffer: &Entity<Buffer>,
22963        ranges: &[Range<text::Anchor>],
22964        cx: &mut App,
22965    ) -> Vec<Range<BufferRow>>;
22966
22967    fn invalidate_inlay_hints(&self, for_buffers: &HashSet<BufferId>, cx: &mut App);
22968
22969    fn inlay_hints(
22970        &self,
22971        invalidate: InvalidationStrategy,
22972        buffer: Entity<Buffer>,
22973        ranges: Vec<Range<text::Anchor>>,
22974        known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
22975        cx: &mut App,
22976    ) -> Option<HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>>>;
22977
22978    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
22979
22980    fn document_highlights(
22981        &self,
22982        buffer: &Entity<Buffer>,
22983        position: text::Anchor,
22984        cx: &mut App,
22985    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
22986
22987    fn definitions(
22988        &self,
22989        buffer: &Entity<Buffer>,
22990        position: text::Anchor,
22991        kind: GotoDefinitionKind,
22992        cx: &mut App,
22993    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>>;
22994
22995    fn range_for_rename(
22996        &self,
22997        buffer: &Entity<Buffer>,
22998        position: text::Anchor,
22999        cx: &mut App,
23000    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
23001
23002    fn perform_rename(
23003        &self,
23004        buffer: &Entity<Buffer>,
23005        position: text::Anchor,
23006        new_name: String,
23007        cx: &mut App,
23008    ) -> Option<Task<Result<ProjectTransaction>>>;
23009}
23010
23011pub trait CompletionProvider {
23012    fn completions(
23013        &self,
23014        excerpt_id: ExcerptId,
23015        buffer: &Entity<Buffer>,
23016        buffer_position: text::Anchor,
23017        trigger: CompletionContext,
23018        window: &mut Window,
23019        cx: &mut Context<Editor>,
23020    ) -> Task<Result<Vec<CompletionResponse>>>;
23021
23022    fn resolve_completions(
23023        &self,
23024        _buffer: Entity<Buffer>,
23025        _completion_indices: Vec<usize>,
23026        _completions: Rc<RefCell<Box<[Completion]>>>,
23027        _cx: &mut Context<Editor>,
23028    ) -> Task<Result<bool>> {
23029        Task::ready(Ok(false))
23030    }
23031
23032    fn apply_additional_edits_for_completion(
23033        &self,
23034        _buffer: Entity<Buffer>,
23035        _completions: Rc<RefCell<Box<[Completion]>>>,
23036        _completion_index: usize,
23037        _push_to_history: bool,
23038        _cx: &mut Context<Editor>,
23039    ) -> Task<Result<Option<language::Transaction>>> {
23040        Task::ready(Ok(None))
23041    }
23042
23043    fn is_completion_trigger(
23044        &self,
23045        buffer: &Entity<Buffer>,
23046        position: language::Anchor,
23047        text: &str,
23048        trigger_in_words: bool,
23049        menu_is_open: bool,
23050        cx: &mut Context<Editor>,
23051    ) -> bool;
23052
23053    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
23054
23055    fn sort_completions(&self) -> bool {
23056        true
23057    }
23058
23059    fn filter_completions(&self) -> bool {
23060        true
23061    }
23062}
23063
23064pub trait CodeActionProvider {
23065    fn id(&self) -> Arc<str>;
23066
23067    fn code_actions(
23068        &self,
23069        buffer: &Entity<Buffer>,
23070        range: Range<text::Anchor>,
23071        window: &mut Window,
23072        cx: &mut App,
23073    ) -> Task<Result<Vec<CodeAction>>>;
23074
23075    fn apply_code_action(
23076        &self,
23077        buffer_handle: Entity<Buffer>,
23078        action: CodeAction,
23079        excerpt_id: ExcerptId,
23080        push_to_history: bool,
23081        window: &mut Window,
23082        cx: &mut App,
23083    ) -> Task<Result<ProjectTransaction>>;
23084}
23085
23086impl CodeActionProvider for Entity<Project> {
23087    fn id(&self) -> Arc<str> {
23088        "project".into()
23089    }
23090
23091    fn code_actions(
23092        &self,
23093        buffer: &Entity<Buffer>,
23094        range: Range<text::Anchor>,
23095        _window: &mut Window,
23096        cx: &mut App,
23097    ) -> Task<Result<Vec<CodeAction>>> {
23098        self.update(cx, |project, cx| {
23099            let code_lens_actions = project.code_lens_actions(buffer, range.clone(), cx);
23100            let code_actions = project.code_actions(buffer, range, None, cx);
23101            cx.background_spawn(async move {
23102                let (code_lens_actions, code_actions) = join(code_lens_actions, code_actions).await;
23103                Ok(code_lens_actions
23104                    .context("code lens fetch")?
23105                    .into_iter()
23106                    .flatten()
23107                    .chain(
23108                        code_actions
23109                            .context("code action fetch")?
23110                            .into_iter()
23111                            .flatten(),
23112                    )
23113                    .collect())
23114            })
23115        })
23116    }
23117
23118    fn apply_code_action(
23119        &self,
23120        buffer_handle: Entity<Buffer>,
23121        action: CodeAction,
23122        _excerpt_id: ExcerptId,
23123        push_to_history: bool,
23124        _window: &mut Window,
23125        cx: &mut App,
23126    ) -> Task<Result<ProjectTransaction>> {
23127        self.update(cx, |project, cx| {
23128            project.apply_code_action(buffer_handle, action, push_to_history, cx)
23129        })
23130    }
23131}
23132
23133fn snippet_completions(
23134    project: &Project,
23135    buffer: &Entity<Buffer>,
23136    buffer_position: text::Anchor,
23137    cx: &mut App,
23138) -> Task<Result<CompletionResponse>> {
23139    let languages = buffer.read(cx).languages_at(buffer_position);
23140    let snippet_store = project.snippets().read(cx);
23141
23142    let scopes: Vec<_> = languages
23143        .iter()
23144        .filter_map(|language| {
23145            let language_name = language.lsp_id();
23146            let snippets = snippet_store.snippets_for(Some(language_name), cx);
23147
23148            if snippets.is_empty() {
23149                None
23150            } else {
23151                Some((language.default_scope(), snippets))
23152            }
23153        })
23154        .collect();
23155
23156    if scopes.is_empty() {
23157        return Task::ready(Ok(CompletionResponse {
23158            completions: vec![],
23159            display_options: CompletionDisplayOptions::default(),
23160            is_incomplete: false,
23161        }));
23162    }
23163
23164    let snapshot = buffer.read(cx).text_snapshot();
23165    let executor = cx.background_executor().clone();
23166
23167    cx.background_spawn(async move {
23168        let mut is_incomplete = false;
23169        let mut completions: Vec<Completion> = Vec::new();
23170        for (scope, snippets) in scopes.into_iter() {
23171            let classifier =
23172                CharClassifier::new(Some(scope)).scope_context(Some(CharScopeContext::Completion));
23173
23174            const MAX_WORD_PREFIX_LEN: usize = 128;
23175            let last_word: String = snapshot
23176                .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
23177                .take(MAX_WORD_PREFIX_LEN)
23178                .take_while(|c| classifier.is_word(*c))
23179                .collect::<String>()
23180                .chars()
23181                .rev()
23182                .collect();
23183
23184            if last_word.is_empty() {
23185                return Ok(CompletionResponse {
23186                    completions: vec![],
23187                    display_options: CompletionDisplayOptions::default(),
23188                    is_incomplete: true,
23189                });
23190            }
23191
23192            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
23193            let to_lsp = |point: &text::Anchor| {
23194                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
23195                point_to_lsp(end)
23196            };
23197            let lsp_end = to_lsp(&buffer_position);
23198
23199            let candidates = snippets
23200                .iter()
23201                .enumerate()
23202                .flat_map(|(ix, snippet)| {
23203                    snippet
23204                        .prefix
23205                        .iter()
23206                        .map(move |prefix| StringMatchCandidate::new(ix, prefix))
23207                })
23208                .collect::<Vec<StringMatchCandidate>>();
23209
23210            const MAX_RESULTS: usize = 100;
23211            let mut matches = fuzzy::match_strings(
23212                &candidates,
23213                &last_word,
23214                last_word.chars().any(|c| c.is_uppercase()),
23215                true,
23216                MAX_RESULTS,
23217                &Default::default(),
23218                executor.clone(),
23219            )
23220            .await;
23221
23222            if matches.len() >= MAX_RESULTS {
23223                is_incomplete = true;
23224            }
23225
23226            // Remove all candidates where the query's start does not match the start of any word in the candidate
23227            if let Some(query_start) = last_word.chars().next() {
23228                matches.retain(|string_match| {
23229                    split_words(&string_match.string).any(|word| {
23230                        // Check that the first codepoint of the word as lowercase matches the first
23231                        // codepoint of the query as lowercase
23232                        word.chars()
23233                            .flat_map(|codepoint| codepoint.to_lowercase())
23234                            .zip(query_start.to_lowercase())
23235                            .all(|(word_cp, query_cp)| word_cp == query_cp)
23236                    })
23237                });
23238            }
23239
23240            let matched_strings = matches
23241                .into_iter()
23242                .map(|m| m.string)
23243                .collect::<HashSet<_>>();
23244
23245            completions.extend(snippets.iter().filter_map(|snippet| {
23246                let matching_prefix = snippet
23247                    .prefix
23248                    .iter()
23249                    .find(|prefix| matched_strings.contains(*prefix))?;
23250                let start = as_offset - last_word.len();
23251                let start = snapshot.anchor_before(start);
23252                let range = start..buffer_position;
23253                let lsp_start = to_lsp(&start);
23254                let lsp_range = lsp::Range {
23255                    start: lsp_start,
23256                    end: lsp_end,
23257                };
23258                Some(Completion {
23259                    replace_range: range,
23260                    new_text: snippet.body.clone(),
23261                    source: CompletionSource::Lsp {
23262                        insert_range: None,
23263                        server_id: LanguageServerId(usize::MAX),
23264                        resolved: true,
23265                        lsp_completion: Box::new(lsp::CompletionItem {
23266                            label: snippet.prefix.first().unwrap().clone(),
23267                            kind: Some(CompletionItemKind::SNIPPET),
23268                            label_details: snippet.description.as_ref().map(|description| {
23269                                lsp::CompletionItemLabelDetails {
23270                                    detail: Some(description.clone()),
23271                                    description: None,
23272                                }
23273                            }),
23274                            insert_text_format: Some(InsertTextFormat::SNIPPET),
23275                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
23276                                lsp::InsertReplaceEdit {
23277                                    new_text: snippet.body.clone(),
23278                                    insert: lsp_range,
23279                                    replace: lsp_range,
23280                                },
23281                            )),
23282                            filter_text: Some(snippet.body.clone()),
23283                            sort_text: Some(char::MAX.to_string()),
23284                            ..lsp::CompletionItem::default()
23285                        }),
23286                        lsp_defaults: None,
23287                    },
23288                    label: CodeLabel::plain(matching_prefix.clone(), None),
23289                    icon_path: None,
23290                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
23291                        single_line: snippet.name.clone().into(),
23292                        plain_text: snippet
23293                            .description
23294                            .clone()
23295                            .map(|description| description.into()),
23296                    }),
23297                    insert_text_mode: None,
23298                    confirm: None,
23299                })
23300            }))
23301        }
23302
23303        Ok(CompletionResponse {
23304            completions,
23305            display_options: CompletionDisplayOptions::default(),
23306            is_incomplete,
23307        })
23308    })
23309}
23310
23311impl CompletionProvider for Entity<Project> {
23312    fn completions(
23313        &self,
23314        _excerpt_id: ExcerptId,
23315        buffer: &Entity<Buffer>,
23316        buffer_position: text::Anchor,
23317        options: CompletionContext,
23318        _window: &mut Window,
23319        cx: &mut Context<Editor>,
23320    ) -> Task<Result<Vec<CompletionResponse>>> {
23321        self.update(cx, |project, cx| {
23322            let snippets = snippet_completions(project, buffer, buffer_position, cx);
23323            let project_completions = project.completions(buffer, buffer_position, options, cx);
23324            cx.background_spawn(async move {
23325                let mut responses = project_completions.await?;
23326                let snippets = snippets.await?;
23327                if !snippets.completions.is_empty() {
23328                    responses.push(snippets);
23329                }
23330                Ok(responses)
23331            })
23332        })
23333    }
23334
23335    fn resolve_completions(
23336        &self,
23337        buffer: Entity<Buffer>,
23338        completion_indices: Vec<usize>,
23339        completions: Rc<RefCell<Box<[Completion]>>>,
23340        cx: &mut Context<Editor>,
23341    ) -> Task<Result<bool>> {
23342        self.update(cx, |project, cx| {
23343            project.lsp_store().update(cx, |lsp_store, cx| {
23344                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
23345            })
23346        })
23347    }
23348
23349    fn apply_additional_edits_for_completion(
23350        &self,
23351        buffer: Entity<Buffer>,
23352        completions: Rc<RefCell<Box<[Completion]>>>,
23353        completion_index: usize,
23354        push_to_history: bool,
23355        cx: &mut Context<Editor>,
23356    ) -> Task<Result<Option<language::Transaction>>> {
23357        self.update(cx, |project, cx| {
23358            project.lsp_store().update(cx, |lsp_store, cx| {
23359                lsp_store.apply_additional_edits_for_completion(
23360                    buffer,
23361                    completions,
23362                    completion_index,
23363                    push_to_history,
23364                    cx,
23365                )
23366            })
23367        })
23368    }
23369
23370    fn is_completion_trigger(
23371        &self,
23372        buffer: &Entity<Buffer>,
23373        position: language::Anchor,
23374        text: &str,
23375        trigger_in_words: bool,
23376        menu_is_open: bool,
23377        cx: &mut Context<Editor>,
23378    ) -> bool {
23379        let mut chars = text.chars();
23380        let char = if let Some(char) = chars.next() {
23381            char
23382        } else {
23383            return false;
23384        };
23385        if chars.next().is_some() {
23386            return false;
23387        }
23388
23389        let buffer = buffer.read(cx);
23390        let snapshot = buffer.snapshot();
23391        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
23392            return false;
23393        }
23394        let classifier = snapshot
23395            .char_classifier_at(position)
23396            .scope_context(Some(CharScopeContext::Completion));
23397        if trigger_in_words && classifier.is_word(char) {
23398            return true;
23399        }
23400
23401        buffer.completion_triggers().contains(text)
23402    }
23403}
23404
23405impl SemanticsProvider for Entity<Project> {
23406    fn hover(
23407        &self,
23408        buffer: &Entity<Buffer>,
23409        position: text::Anchor,
23410        cx: &mut App,
23411    ) -> Option<Task<Option<Vec<project::Hover>>>> {
23412        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
23413    }
23414
23415    fn document_highlights(
23416        &self,
23417        buffer: &Entity<Buffer>,
23418        position: text::Anchor,
23419        cx: &mut App,
23420    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
23421        Some(self.update(cx, |project, cx| {
23422            project.document_highlights(buffer, position, cx)
23423        }))
23424    }
23425
23426    fn definitions(
23427        &self,
23428        buffer: &Entity<Buffer>,
23429        position: text::Anchor,
23430        kind: GotoDefinitionKind,
23431        cx: &mut App,
23432    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>> {
23433        Some(self.update(cx, |project, cx| match kind {
23434            GotoDefinitionKind::Symbol => project.definitions(buffer, position, cx),
23435            GotoDefinitionKind::Declaration => project.declarations(buffer, position, cx),
23436            GotoDefinitionKind::Type => project.type_definitions(buffer, position, cx),
23437            GotoDefinitionKind::Implementation => project.implementations(buffer, position, cx),
23438        }))
23439    }
23440
23441    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
23442        self.update(cx, |project, cx| {
23443            if project
23444                .active_debug_session(cx)
23445                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
23446            {
23447                return true;
23448            }
23449
23450            buffer.update(cx, |buffer, cx| {
23451                project.any_language_server_supports_inlay_hints(buffer, cx)
23452            })
23453        })
23454    }
23455
23456    fn inline_values(
23457        &self,
23458        buffer_handle: Entity<Buffer>,
23459        range: Range<text::Anchor>,
23460        cx: &mut App,
23461    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
23462        self.update(cx, |project, cx| {
23463            let (session, active_stack_frame) = project.active_debug_session(cx)?;
23464
23465            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
23466        })
23467    }
23468
23469    fn applicable_inlay_chunks(
23470        &self,
23471        buffer: &Entity<Buffer>,
23472        ranges: &[Range<text::Anchor>],
23473        cx: &mut App,
23474    ) -> Vec<Range<BufferRow>> {
23475        self.read(cx).lsp_store().update(cx, |lsp_store, cx| {
23476            lsp_store.applicable_inlay_chunks(buffer, ranges, cx)
23477        })
23478    }
23479
23480    fn invalidate_inlay_hints(&self, for_buffers: &HashSet<BufferId>, cx: &mut App) {
23481        self.read(cx).lsp_store().update(cx, |lsp_store, _| {
23482            lsp_store.invalidate_inlay_hints(for_buffers)
23483        });
23484    }
23485
23486    fn inlay_hints(
23487        &self,
23488        invalidate: InvalidationStrategy,
23489        buffer: Entity<Buffer>,
23490        ranges: Vec<Range<text::Anchor>>,
23491        known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
23492        cx: &mut App,
23493    ) -> Option<HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>>> {
23494        Some(self.read(cx).lsp_store().update(cx, |lsp_store, cx| {
23495            lsp_store.inlay_hints(invalidate, buffer, ranges, known_chunks, cx)
23496        }))
23497    }
23498
23499    fn range_for_rename(
23500        &self,
23501        buffer: &Entity<Buffer>,
23502        position: text::Anchor,
23503        cx: &mut App,
23504    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
23505        Some(self.update(cx, |project, cx| {
23506            let buffer = buffer.clone();
23507            let task = project.prepare_rename(buffer.clone(), position, cx);
23508            cx.spawn(async move |_, cx| {
23509                Ok(match task.await? {
23510                    PrepareRenameResponse::Success(range) => Some(range),
23511                    PrepareRenameResponse::InvalidPosition => None,
23512                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
23513                        // Fallback on using TreeSitter info to determine identifier range
23514                        buffer.read_with(cx, |buffer, _| {
23515                            let snapshot = buffer.snapshot();
23516                            let (range, kind) = snapshot.surrounding_word(position, None);
23517                            if kind != Some(CharKind::Word) {
23518                                return None;
23519                            }
23520                            Some(
23521                                snapshot.anchor_before(range.start)
23522                                    ..snapshot.anchor_after(range.end),
23523                            )
23524                        })?
23525                    }
23526                })
23527            })
23528        }))
23529    }
23530
23531    fn perform_rename(
23532        &self,
23533        buffer: &Entity<Buffer>,
23534        position: text::Anchor,
23535        new_name: String,
23536        cx: &mut App,
23537    ) -> Option<Task<Result<ProjectTransaction>>> {
23538        Some(self.update(cx, |project, cx| {
23539            project.perform_rename(buffer.clone(), position, new_name, cx)
23540        }))
23541    }
23542}
23543
23544fn consume_contiguous_rows(
23545    contiguous_row_selections: &mut Vec<Selection<Point>>,
23546    selection: &Selection<Point>,
23547    display_map: &DisplaySnapshot,
23548    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
23549) -> (MultiBufferRow, MultiBufferRow) {
23550    contiguous_row_selections.push(selection.clone());
23551    let start_row = starting_row(selection, display_map);
23552    let mut end_row = ending_row(selection, display_map);
23553
23554    while let Some(next_selection) = selections.peek() {
23555        if next_selection.start.row <= end_row.0 {
23556            end_row = ending_row(next_selection, display_map);
23557            contiguous_row_selections.push(selections.next().unwrap().clone());
23558        } else {
23559            break;
23560        }
23561    }
23562    (start_row, end_row)
23563}
23564
23565fn starting_row(selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
23566    if selection.start.column > 0 {
23567        MultiBufferRow(display_map.prev_line_boundary(selection.start).0.row)
23568    } else {
23569        MultiBufferRow(selection.start.row)
23570    }
23571}
23572
23573fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
23574    if next_selection.end.column > 0 || next_selection.is_empty() {
23575        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
23576    } else {
23577        MultiBufferRow(next_selection.end.row)
23578    }
23579}
23580
23581impl EditorSnapshot {
23582    pub fn remote_selections_in_range<'a>(
23583        &'a self,
23584        range: &'a Range<Anchor>,
23585        collaboration_hub: &dyn CollaborationHub,
23586        cx: &'a App,
23587    ) -> impl 'a + Iterator<Item = RemoteSelection> {
23588        let participant_names = collaboration_hub.user_names(cx);
23589        let participant_indices = collaboration_hub.user_participant_indices(cx);
23590        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
23591        let collaborators_by_replica_id = collaborators_by_peer_id
23592            .values()
23593            .map(|collaborator| (collaborator.replica_id, collaborator))
23594            .collect::<HashMap<_, _>>();
23595        self.buffer_snapshot()
23596            .selections_in_range(range, false)
23597            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
23598                if replica_id == ReplicaId::AGENT {
23599                    Some(RemoteSelection {
23600                        replica_id,
23601                        selection,
23602                        cursor_shape,
23603                        line_mode,
23604                        collaborator_id: CollaboratorId::Agent,
23605                        user_name: Some("Agent".into()),
23606                        color: cx.theme().players().agent(),
23607                    })
23608                } else {
23609                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
23610                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
23611                    let user_name = participant_names.get(&collaborator.user_id).cloned();
23612                    Some(RemoteSelection {
23613                        replica_id,
23614                        selection,
23615                        cursor_shape,
23616                        line_mode,
23617                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
23618                        user_name,
23619                        color: if let Some(index) = participant_index {
23620                            cx.theme().players().color_for_participant(index.0)
23621                        } else {
23622                            cx.theme().players().absent()
23623                        },
23624                    })
23625                }
23626            })
23627    }
23628
23629    pub fn hunks_for_ranges(
23630        &self,
23631        ranges: impl IntoIterator<Item = Range<Point>>,
23632    ) -> Vec<MultiBufferDiffHunk> {
23633        let mut hunks = Vec::new();
23634        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
23635            HashMap::default();
23636        for query_range in ranges {
23637            let query_rows =
23638                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
23639            for hunk in self.buffer_snapshot().diff_hunks_in_range(
23640                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
23641            ) {
23642                // Include deleted hunks that are adjacent to the query range, because
23643                // otherwise they would be missed.
23644                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
23645                if hunk.status().is_deleted() {
23646                    intersects_range |= hunk.row_range.start == query_rows.end;
23647                    intersects_range |= hunk.row_range.end == query_rows.start;
23648                }
23649                if intersects_range {
23650                    if !processed_buffer_rows
23651                        .entry(hunk.buffer_id)
23652                        .or_default()
23653                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
23654                    {
23655                        continue;
23656                    }
23657                    hunks.push(hunk);
23658                }
23659            }
23660        }
23661
23662        hunks
23663    }
23664
23665    fn display_diff_hunks_for_rows<'a>(
23666        &'a self,
23667        display_rows: Range<DisplayRow>,
23668        folded_buffers: &'a HashSet<BufferId>,
23669    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
23670        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
23671        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
23672
23673        self.buffer_snapshot()
23674            .diff_hunks_in_range(buffer_start..buffer_end)
23675            .filter_map(|hunk| {
23676                if folded_buffers.contains(&hunk.buffer_id) {
23677                    return None;
23678                }
23679
23680                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
23681                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
23682
23683                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
23684                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
23685
23686                let display_hunk = if hunk_display_start.column() != 0 {
23687                    DisplayDiffHunk::Folded {
23688                        display_row: hunk_display_start.row(),
23689                    }
23690                } else {
23691                    let mut end_row = hunk_display_end.row();
23692                    if hunk_display_end.column() > 0 {
23693                        end_row.0 += 1;
23694                    }
23695                    let is_created_file = hunk.is_created_file();
23696                    DisplayDiffHunk::Unfolded {
23697                        status: hunk.status(),
23698                        diff_base_byte_range: hunk.diff_base_byte_range,
23699                        display_row_range: hunk_display_start.row()..end_row,
23700                        multi_buffer_range: Anchor::range_in_buffer(
23701                            hunk.excerpt_id,
23702                            hunk.buffer_id,
23703                            hunk.buffer_range,
23704                        ),
23705                        is_created_file,
23706                    }
23707                };
23708
23709                Some(display_hunk)
23710            })
23711    }
23712
23713    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
23714        self.display_snapshot
23715            .buffer_snapshot()
23716            .language_at(position)
23717    }
23718
23719    pub fn is_focused(&self) -> bool {
23720        self.is_focused
23721    }
23722
23723    pub fn placeholder_text(&self) -> Option<String> {
23724        self.placeholder_display_snapshot
23725            .as_ref()
23726            .map(|display_map| display_map.text())
23727    }
23728
23729    pub fn scroll_position(&self) -> gpui::Point<ScrollOffset> {
23730        self.scroll_anchor.scroll_position(&self.display_snapshot)
23731    }
23732
23733    fn gutter_dimensions(
23734        &self,
23735        font_id: FontId,
23736        font_size: Pixels,
23737        max_line_number_width: Pixels,
23738        cx: &App,
23739    ) -> Option<GutterDimensions> {
23740        if !self.show_gutter {
23741            return None;
23742        }
23743
23744        let ch_width = cx.text_system().ch_width(font_id, font_size).log_err()?;
23745        let ch_advance = cx.text_system().ch_advance(font_id, font_size).log_err()?;
23746
23747        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
23748            matches!(
23749                ProjectSettings::get_global(cx).git.git_gutter,
23750                GitGutterSetting::TrackedFiles
23751            )
23752        });
23753        let gutter_settings = EditorSettings::get_global(cx).gutter;
23754        let show_line_numbers = self
23755            .show_line_numbers
23756            .unwrap_or(gutter_settings.line_numbers);
23757        let line_gutter_width = if show_line_numbers {
23758            // Avoid flicker-like gutter resizes when the line number gains another digit by
23759            // only resizing the gutter on files with > 10**min_line_number_digits lines.
23760            let min_width_for_number_on_gutter =
23761                ch_advance * gutter_settings.min_line_number_digits as f32;
23762            max_line_number_width.max(min_width_for_number_on_gutter)
23763        } else {
23764            0.0.into()
23765        };
23766
23767        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
23768        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
23769
23770        let git_blame_entries_width =
23771            self.git_blame_gutter_max_author_length
23772                .map(|max_author_length| {
23773                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
23774                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
23775
23776                    /// The number of characters to dedicate to gaps and margins.
23777                    const SPACING_WIDTH: usize = 4;
23778
23779                    let max_char_count = max_author_length.min(renderer.max_author_length())
23780                        + ::git::SHORT_SHA_LENGTH
23781                        + MAX_RELATIVE_TIMESTAMP.len()
23782                        + SPACING_WIDTH;
23783
23784                    ch_advance * max_char_count
23785                });
23786
23787        let is_singleton = self.buffer_snapshot().is_singleton();
23788
23789        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
23790        left_padding += if !is_singleton {
23791            ch_width * 4.0
23792        } else if show_runnables || show_breakpoints {
23793            ch_width * 3.0
23794        } else if show_git_gutter && show_line_numbers {
23795            ch_width * 2.0
23796        } else if show_git_gutter || show_line_numbers {
23797            ch_width
23798        } else {
23799            px(0.)
23800        };
23801
23802        let shows_folds = is_singleton && gutter_settings.folds;
23803
23804        let right_padding = if shows_folds && show_line_numbers {
23805            ch_width * 4.0
23806        } else if shows_folds || (!is_singleton && show_line_numbers) {
23807            ch_width * 3.0
23808        } else if show_line_numbers {
23809            ch_width
23810        } else {
23811            px(0.)
23812        };
23813
23814        Some(GutterDimensions {
23815            left_padding,
23816            right_padding,
23817            width: line_gutter_width + left_padding + right_padding,
23818            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
23819            git_blame_entries_width,
23820        })
23821    }
23822
23823    pub fn render_crease_toggle(
23824        &self,
23825        buffer_row: MultiBufferRow,
23826        row_contains_cursor: bool,
23827        editor: Entity<Editor>,
23828        window: &mut Window,
23829        cx: &mut App,
23830    ) -> Option<AnyElement> {
23831        let folded = self.is_line_folded(buffer_row);
23832        let mut is_foldable = false;
23833
23834        if let Some(crease) = self
23835            .crease_snapshot
23836            .query_row(buffer_row, self.buffer_snapshot())
23837        {
23838            is_foldable = true;
23839            match crease {
23840                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
23841                    if let Some(render_toggle) = render_toggle {
23842                        let toggle_callback =
23843                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
23844                                if folded {
23845                                    editor.update(cx, |editor, cx| {
23846                                        editor.fold_at(buffer_row, window, cx)
23847                                    });
23848                                } else {
23849                                    editor.update(cx, |editor, cx| {
23850                                        editor.unfold_at(buffer_row, window, cx)
23851                                    });
23852                                }
23853                            });
23854                        return Some((render_toggle)(
23855                            buffer_row,
23856                            folded,
23857                            toggle_callback,
23858                            window,
23859                            cx,
23860                        ));
23861                    }
23862                }
23863            }
23864        }
23865
23866        is_foldable |= self.starts_indent(buffer_row);
23867
23868        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
23869            Some(
23870                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
23871                    .toggle_state(folded)
23872                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
23873                        if folded {
23874                            this.unfold_at(buffer_row, window, cx);
23875                        } else {
23876                            this.fold_at(buffer_row, window, cx);
23877                        }
23878                    }))
23879                    .into_any_element(),
23880            )
23881        } else {
23882            None
23883        }
23884    }
23885
23886    pub fn render_crease_trailer(
23887        &self,
23888        buffer_row: MultiBufferRow,
23889        window: &mut Window,
23890        cx: &mut App,
23891    ) -> Option<AnyElement> {
23892        let folded = self.is_line_folded(buffer_row);
23893        if let Crease::Inline { render_trailer, .. } = self
23894            .crease_snapshot
23895            .query_row(buffer_row, self.buffer_snapshot())?
23896        {
23897            let render_trailer = render_trailer.as_ref()?;
23898            Some(render_trailer(buffer_row, folded, window, cx))
23899        } else {
23900            None
23901        }
23902    }
23903}
23904
23905impl Deref for EditorSnapshot {
23906    type Target = DisplaySnapshot;
23907
23908    fn deref(&self) -> &Self::Target {
23909        &self.display_snapshot
23910    }
23911}
23912
23913#[derive(Clone, Debug, PartialEq, Eq)]
23914pub enum EditorEvent {
23915    InputIgnored {
23916        text: Arc<str>,
23917    },
23918    InputHandled {
23919        utf16_range_to_replace: Option<Range<isize>>,
23920        text: Arc<str>,
23921    },
23922    ExcerptsAdded {
23923        buffer: Entity<Buffer>,
23924        predecessor: ExcerptId,
23925        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
23926    },
23927    ExcerptsRemoved {
23928        ids: Vec<ExcerptId>,
23929        removed_buffer_ids: Vec<BufferId>,
23930    },
23931    BufferFoldToggled {
23932        ids: Vec<ExcerptId>,
23933        folded: bool,
23934    },
23935    ExcerptsEdited {
23936        ids: Vec<ExcerptId>,
23937    },
23938    ExcerptsExpanded {
23939        ids: Vec<ExcerptId>,
23940    },
23941    BufferEdited,
23942    Edited {
23943        transaction_id: clock::Lamport,
23944    },
23945    Reparsed(BufferId),
23946    Focused,
23947    FocusedIn,
23948    Blurred,
23949    DirtyChanged,
23950    Saved,
23951    TitleChanged,
23952    SelectionsChanged {
23953        local: bool,
23954    },
23955    ScrollPositionChanged {
23956        local: bool,
23957        autoscroll: bool,
23958    },
23959    TransactionUndone {
23960        transaction_id: clock::Lamport,
23961    },
23962    TransactionBegun {
23963        transaction_id: clock::Lamport,
23964    },
23965    CursorShapeChanged,
23966    BreadcrumbsChanged,
23967    PushedToNavHistory {
23968        anchor: Anchor,
23969        is_deactivate: bool,
23970    },
23971}
23972
23973impl EventEmitter<EditorEvent> for Editor {}
23974
23975impl Focusable for Editor {
23976    fn focus_handle(&self, _cx: &App) -> FocusHandle {
23977        self.focus_handle.clone()
23978    }
23979}
23980
23981impl Render for Editor {
23982    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23983        let settings = ThemeSettings::get_global(cx);
23984
23985        let mut text_style = match self.mode {
23986            EditorMode::SingleLine | EditorMode::AutoHeight { .. } => TextStyle {
23987                color: cx.theme().colors().editor_foreground,
23988                font_family: settings.ui_font.family.clone(),
23989                font_features: settings.ui_font.features.clone(),
23990                font_fallbacks: settings.ui_font.fallbacks.clone(),
23991                font_size: rems(0.875).into(),
23992                font_weight: settings.ui_font.weight,
23993                line_height: relative(settings.buffer_line_height.value()),
23994                ..Default::default()
23995            },
23996            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
23997                color: cx.theme().colors().editor_foreground,
23998                font_family: settings.buffer_font.family.clone(),
23999                font_features: settings.buffer_font.features.clone(),
24000                font_fallbacks: settings.buffer_font.fallbacks.clone(),
24001                font_size: settings.buffer_font_size(cx).into(),
24002                font_weight: settings.buffer_font.weight,
24003                line_height: relative(settings.buffer_line_height.value()),
24004                ..Default::default()
24005            },
24006        };
24007        if let Some(text_style_refinement) = &self.text_style_refinement {
24008            text_style.refine(text_style_refinement)
24009        }
24010
24011        let background = match self.mode {
24012            EditorMode::SingleLine => cx.theme().system().transparent,
24013            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
24014            EditorMode::Full { .. } => cx.theme().colors().editor_background,
24015            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
24016        };
24017
24018        EditorElement::new(
24019            &cx.entity(),
24020            EditorStyle {
24021                background,
24022                border: cx.theme().colors().border,
24023                local_player: cx.theme().players().local(),
24024                text: text_style,
24025                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
24026                syntax: cx.theme().syntax().clone(),
24027                status: cx.theme().status().clone(),
24028                inlay_hints_style: make_inlay_hints_style(cx),
24029                edit_prediction_styles: make_suggestion_styles(cx),
24030                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
24031                show_underlines: self.diagnostics_enabled(),
24032            },
24033        )
24034    }
24035}
24036
24037impl EntityInputHandler for Editor {
24038    fn text_for_range(
24039        &mut self,
24040        range_utf16: Range<usize>,
24041        adjusted_range: &mut Option<Range<usize>>,
24042        _: &mut Window,
24043        cx: &mut Context<Self>,
24044    ) -> Option<String> {
24045        let snapshot = self.buffer.read(cx).read(cx);
24046        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
24047        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
24048        if (start.0..end.0) != range_utf16 {
24049            adjusted_range.replace(start.0..end.0);
24050        }
24051        Some(snapshot.text_for_range(start..end).collect())
24052    }
24053
24054    fn selected_text_range(
24055        &mut self,
24056        ignore_disabled_input: bool,
24057        _: &mut Window,
24058        cx: &mut Context<Self>,
24059    ) -> Option<UTF16Selection> {
24060        // Prevent the IME menu from appearing when holding down an alphabetic key
24061        // while input is disabled.
24062        if !ignore_disabled_input && !self.input_enabled {
24063            return None;
24064        }
24065
24066        let selection = self
24067            .selections
24068            .newest::<OffsetUtf16>(&self.display_snapshot(cx));
24069        let range = selection.range();
24070
24071        Some(UTF16Selection {
24072            range: range.start.0..range.end.0,
24073            reversed: selection.reversed,
24074        })
24075    }
24076
24077    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
24078        let snapshot = self.buffer.read(cx).read(cx);
24079        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
24080        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
24081    }
24082
24083    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
24084        self.clear_highlights::<InputComposition>(cx);
24085        self.ime_transaction.take();
24086    }
24087
24088    fn replace_text_in_range(
24089        &mut self,
24090        range_utf16: Option<Range<usize>>,
24091        text: &str,
24092        window: &mut Window,
24093        cx: &mut Context<Self>,
24094    ) {
24095        if !self.input_enabled {
24096            cx.emit(EditorEvent::InputIgnored { text: text.into() });
24097            return;
24098        }
24099
24100        self.transact(window, cx, |this, window, cx| {
24101            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
24102                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
24103                Some(this.selection_replacement_ranges(range_utf16, cx))
24104            } else {
24105                this.marked_text_ranges(cx)
24106            };
24107
24108            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
24109                let newest_selection_id = this.selections.newest_anchor().id;
24110                this.selections
24111                    .all::<OffsetUtf16>(&this.display_snapshot(cx))
24112                    .iter()
24113                    .zip(ranges_to_replace.iter())
24114                    .find_map(|(selection, range)| {
24115                        if selection.id == newest_selection_id {
24116                            Some(
24117                                (range.start.0 as isize - selection.head().0 as isize)
24118                                    ..(range.end.0 as isize - selection.head().0 as isize),
24119                            )
24120                        } else {
24121                            None
24122                        }
24123                    })
24124            });
24125
24126            cx.emit(EditorEvent::InputHandled {
24127                utf16_range_to_replace: range_to_replace,
24128                text: text.into(),
24129            });
24130
24131            if let Some(new_selected_ranges) = new_selected_ranges {
24132                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
24133                    selections.select_ranges(new_selected_ranges)
24134                });
24135                this.backspace(&Default::default(), window, cx);
24136            }
24137
24138            this.handle_input(text, window, cx);
24139        });
24140
24141        if let Some(transaction) = self.ime_transaction {
24142            self.buffer.update(cx, |buffer, cx| {
24143                buffer.group_until_transaction(transaction, cx);
24144            });
24145        }
24146
24147        self.unmark_text(window, cx);
24148    }
24149
24150    fn replace_and_mark_text_in_range(
24151        &mut self,
24152        range_utf16: Option<Range<usize>>,
24153        text: &str,
24154        new_selected_range_utf16: Option<Range<usize>>,
24155        window: &mut Window,
24156        cx: &mut Context<Self>,
24157    ) {
24158        if !self.input_enabled {
24159            return;
24160        }
24161
24162        let transaction = self.transact(window, cx, |this, window, cx| {
24163            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
24164                let snapshot = this.buffer.read(cx).read(cx);
24165                if let Some(relative_range_utf16) = range_utf16.as_ref() {
24166                    for marked_range in &mut marked_ranges {
24167                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
24168                        marked_range.start.0 += relative_range_utf16.start;
24169                        marked_range.start =
24170                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
24171                        marked_range.end =
24172                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
24173                    }
24174                }
24175                Some(marked_ranges)
24176            } else if let Some(range_utf16) = range_utf16 {
24177                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
24178                Some(this.selection_replacement_ranges(range_utf16, cx))
24179            } else {
24180                None
24181            };
24182
24183            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
24184                let newest_selection_id = this.selections.newest_anchor().id;
24185                this.selections
24186                    .all::<OffsetUtf16>(&this.display_snapshot(cx))
24187                    .iter()
24188                    .zip(ranges_to_replace.iter())
24189                    .find_map(|(selection, range)| {
24190                        if selection.id == newest_selection_id {
24191                            Some(
24192                                (range.start.0 as isize - selection.head().0 as isize)
24193                                    ..(range.end.0 as isize - selection.head().0 as isize),
24194                            )
24195                        } else {
24196                            None
24197                        }
24198                    })
24199            });
24200
24201            cx.emit(EditorEvent::InputHandled {
24202                utf16_range_to_replace: range_to_replace,
24203                text: text.into(),
24204            });
24205
24206            if let Some(ranges) = ranges_to_replace {
24207                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
24208                    s.select_ranges(ranges)
24209                });
24210            }
24211
24212            let marked_ranges = {
24213                let snapshot = this.buffer.read(cx).read(cx);
24214                this.selections
24215                    .disjoint_anchors_arc()
24216                    .iter()
24217                    .map(|selection| {
24218                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
24219                    })
24220                    .collect::<Vec<_>>()
24221            };
24222
24223            if text.is_empty() {
24224                this.unmark_text(window, cx);
24225            } else {
24226                this.highlight_text::<InputComposition>(
24227                    marked_ranges.clone(),
24228                    HighlightStyle {
24229                        underline: Some(UnderlineStyle {
24230                            thickness: px(1.),
24231                            color: None,
24232                            wavy: false,
24233                        }),
24234                        ..Default::default()
24235                    },
24236                    cx,
24237                );
24238            }
24239
24240            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
24241            let use_autoclose = this.use_autoclose;
24242            let use_auto_surround = this.use_auto_surround;
24243            this.set_use_autoclose(false);
24244            this.set_use_auto_surround(false);
24245            this.handle_input(text, window, cx);
24246            this.set_use_autoclose(use_autoclose);
24247            this.set_use_auto_surround(use_auto_surround);
24248
24249            if let Some(new_selected_range) = new_selected_range_utf16 {
24250                let snapshot = this.buffer.read(cx).read(cx);
24251                let new_selected_ranges = marked_ranges
24252                    .into_iter()
24253                    .map(|marked_range| {
24254                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
24255                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
24256                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
24257                        snapshot.clip_offset_utf16(new_start, Bias::Left)
24258                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
24259                    })
24260                    .collect::<Vec<_>>();
24261
24262                drop(snapshot);
24263                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
24264                    selections.select_ranges(new_selected_ranges)
24265                });
24266            }
24267        });
24268
24269        self.ime_transaction = self.ime_transaction.or(transaction);
24270        if let Some(transaction) = self.ime_transaction {
24271            self.buffer.update(cx, |buffer, cx| {
24272                buffer.group_until_transaction(transaction, cx);
24273            });
24274        }
24275
24276        if self.text_highlights::<InputComposition>(cx).is_none() {
24277            self.ime_transaction.take();
24278        }
24279    }
24280
24281    fn bounds_for_range(
24282        &mut self,
24283        range_utf16: Range<usize>,
24284        element_bounds: gpui::Bounds<Pixels>,
24285        window: &mut Window,
24286        cx: &mut Context<Self>,
24287    ) -> Option<gpui::Bounds<Pixels>> {
24288        let text_layout_details = self.text_layout_details(window);
24289        let CharacterDimensions {
24290            em_width,
24291            em_advance,
24292            line_height,
24293        } = self.character_dimensions(window);
24294
24295        let snapshot = self.snapshot(window, cx);
24296        let scroll_position = snapshot.scroll_position();
24297        let scroll_left = scroll_position.x * ScrollOffset::from(em_advance);
24298
24299        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
24300        let x = Pixels::from(
24301            ScrollOffset::from(
24302                snapshot.x_for_display_point(start, &text_layout_details)
24303                    + self.gutter_dimensions.full_width(),
24304            ) - scroll_left,
24305        );
24306        let y = line_height * (start.row().as_f64() - scroll_position.y) as f32;
24307
24308        Some(Bounds {
24309            origin: element_bounds.origin + point(x, y),
24310            size: size(em_width, line_height),
24311        })
24312    }
24313
24314    fn character_index_for_point(
24315        &mut self,
24316        point: gpui::Point<Pixels>,
24317        _window: &mut Window,
24318        _cx: &mut Context<Self>,
24319    ) -> Option<usize> {
24320        let position_map = self.last_position_map.as_ref()?;
24321        if !position_map.text_hitbox.contains(&point) {
24322            return None;
24323        }
24324        let display_point = position_map.point_for_position(point).previous_valid;
24325        let anchor = position_map
24326            .snapshot
24327            .display_point_to_anchor(display_point, Bias::Left);
24328        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot());
24329        Some(utf16_offset.0)
24330    }
24331
24332    fn accepts_text_input(&self, _window: &mut Window, _cx: &mut Context<Self>) -> bool {
24333        self.input_enabled
24334    }
24335}
24336
24337trait SelectionExt {
24338    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
24339    fn spanned_rows(
24340        &self,
24341        include_end_if_at_line_start: bool,
24342        map: &DisplaySnapshot,
24343    ) -> Range<MultiBufferRow>;
24344}
24345
24346impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
24347    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
24348        let start = self
24349            .start
24350            .to_point(map.buffer_snapshot())
24351            .to_display_point(map);
24352        let end = self
24353            .end
24354            .to_point(map.buffer_snapshot())
24355            .to_display_point(map);
24356        if self.reversed {
24357            end..start
24358        } else {
24359            start..end
24360        }
24361    }
24362
24363    fn spanned_rows(
24364        &self,
24365        include_end_if_at_line_start: bool,
24366        map: &DisplaySnapshot,
24367    ) -> Range<MultiBufferRow> {
24368        let start = self.start.to_point(map.buffer_snapshot());
24369        let mut end = self.end.to_point(map.buffer_snapshot());
24370        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
24371            end.row -= 1;
24372        }
24373
24374        let buffer_start = map.prev_line_boundary(start).0;
24375        let buffer_end = map.next_line_boundary(end).0;
24376        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
24377    }
24378}
24379
24380impl<T: InvalidationRegion> InvalidationStack<T> {
24381    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
24382    where
24383        S: Clone + ToOffset,
24384    {
24385        while let Some(region) = self.last() {
24386            let all_selections_inside_invalidation_ranges =
24387                if selections.len() == region.ranges().len() {
24388                    selections
24389                        .iter()
24390                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
24391                        .all(|(selection, invalidation_range)| {
24392                            let head = selection.head().to_offset(buffer);
24393                            invalidation_range.start <= head && invalidation_range.end >= head
24394                        })
24395                } else {
24396                    false
24397                };
24398
24399            if all_selections_inside_invalidation_ranges {
24400                break;
24401            } else {
24402                self.pop();
24403            }
24404        }
24405    }
24406}
24407
24408impl<T> Default for InvalidationStack<T> {
24409    fn default() -> Self {
24410        Self(Default::default())
24411    }
24412}
24413
24414impl<T> Deref for InvalidationStack<T> {
24415    type Target = Vec<T>;
24416
24417    fn deref(&self) -> &Self::Target {
24418        &self.0
24419    }
24420}
24421
24422impl<T> DerefMut for InvalidationStack<T> {
24423    fn deref_mut(&mut self) -> &mut Self::Target {
24424        &mut self.0
24425    }
24426}
24427
24428impl InvalidationRegion for SnippetState {
24429    fn ranges(&self) -> &[Range<Anchor>] {
24430        &self.ranges[self.active_index]
24431    }
24432}
24433
24434fn edit_prediction_edit_text(
24435    current_snapshot: &BufferSnapshot,
24436    edits: &[(Range<Anchor>, impl AsRef<str>)],
24437    edit_preview: &EditPreview,
24438    include_deletions: bool,
24439    cx: &App,
24440) -> HighlightedText {
24441    let edits = edits
24442        .iter()
24443        .map(|(anchor, text)| (anchor.start.text_anchor..anchor.end.text_anchor, text))
24444        .collect::<Vec<_>>();
24445
24446    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
24447}
24448
24449fn edit_prediction_fallback_text(edits: &[(Range<Anchor>, Arc<str>)], cx: &App) -> HighlightedText {
24450    // Fallback for providers that don't provide edit_preview (like Copilot/Supermaven)
24451    // Just show the raw edit text with basic styling
24452    let mut text = String::new();
24453    let mut highlights = Vec::new();
24454
24455    let insertion_highlight_style = HighlightStyle {
24456        color: Some(cx.theme().colors().text),
24457        ..Default::default()
24458    };
24459
24460    for (_, edit_text) in edits {
24461        let start_offset = text.len();
24462        text.push_str(edit_text);
24463        let end_offset = text.len();
24464
24465        if start_offset < end_offset {
24466            highlights.push((start_offset..end_offset, insertion_highlight_style));
24467        }
24468    }
24469
24470    HighlightedText {
24471        text: text.into(),
24472        highlights,
24473    }
24474}
24475
24476pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
24477    match severity {
24478        lsp::DiagnosticSeverity::ERROR => colors.error,
24479        lsp::DiagnosticSeverity::WARNING => colors.warning,
24480        lsp::DiagnosticSeverity::INFORMATION => colors.info,
24481        lsp::DiagnosticSeverity::HINT => colors.info,
24482        _ => colors.ignored,
24483    }
24484}
24485
24486pub fn styled_runs_for_code_label<'a>(
24487    label: &'a CodeLabel,
24488    syntax_theme: &'a theme::SyntaxTheme,
24489) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
24490    let fade_out = HighlightStyle {
24491        fade_out: Some(0.35),
24492        ..Default::default()
24493    };
24494
24495    let mut prev_end = label.filter_range.end;
24496    label
24497        .runs
24498        .iter()
24499        .enumerate()
24500        .flat_map(move |(ix, (range, highlight_id))| {
24501            let style = if let Some(style) = highlight_id.style(syntax_theme) {
24502                style
24503            } else {
24504                return Default::default();
24505            };
24506            let muted_style = style.highlight(fade_out);
24507
24508            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
24509            if range.start >= label.filter_range.end {
24510                if range.start > prev_end {
24511                    runs.push((prev_end..range.start, fade_out));
24512                }
24513                runs.push((range.clone(), muted_style));
24514            } else if range.end <= label.filter_range.end {
24515                runs.push((range.clone(), style));
24516            } else {
24517                runs.push((range.start..label.filter_range.end, style));
24518                runs.push((label.filter_range.end..range.end, muted_style));
24519            }
24520            prev_end = cmp::max(prev_end, range.end);
24521
24522            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
24523                runs.push((prev_end..label.text.len(), fade_out));
24524            }
24525
24526            runs
24527        })
24528}
24529
24530pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
24531    let mut prev_index = 0;
24532    let mut prev_codepoint: Option<char> = None;
24533    text.char_indices()
24534        .chain([(text.len(), '\0')])
24535        .filter_map(move |(index, codepoint)| {
24536            let prev_codepoint = prev_codepoint.replace(codepoint)?;
24537            let is_boundary = index == text.len()
24538                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
24539                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
24540            if is_boundary {
24541                let chunk = &text[prev_index..index];
24542                prev_index = index;
24543                Some(chunk)
24544            } else {
24545                None
24546            }
24547        })
24548}
24549
24550pub trait RangeToAnchorExt: Sized {
24551    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
24552
24553    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
24554        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot());
24555        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
24556    }
24557}
24558
24559impl<T: ToOffset> RangeToAnchorExt for Range<T> {
24560    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
24561        let start_offset = self.start.to_offset(snapshot);
24562        let end_offset = self.end.to_offset(snapshot);
24563        if start_offset == end_offset {
24564            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
24565        } else {
24566            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
24567        }
24568    }
24569}
24570
24571pub trait RowExt {
24572    fn as_f64(&self) -> f64;
24573
24574    fn next_row(&self) -> Self;
24575
24576    fn previous_row(&self) -> Self;
24577
24578    fn minus(&self, other: Self) -> u32;
24579}
24580
24581impl RowExt for DisplayRow {
24582    fn as_f64(&self) -> f64 {
24583        self.0 as _
24584    }
24585
24586    fn next_row(&self) -> Self {
24587        Self(self.0 + 1)
24588    }
24589
24590    fn previous_row(&self) -> Self {
24591        Self(self.0.saturating_sub(1))
24592    }
24593
24594    fn minus(&self, other: Self) -> u32 {
24595        self.0 - other.0
24596    }
24597}
24598
24599impl RowExt for MultiBufferRow {
24600    fn as_f64(&self) -> f64 {
24601        self.0 as _
24602    }
24603
24604    fn next_row(&self) -> Self {
24605        Self(self.0 + 1)
24606    }
24607
24608    fn previous_row(&self) -> Self {
24609        Self(self.0.saturating_sub(1))
24610    }
24611
24612    fn minus(&self, other: Self) -> u32 {
24613        self.0 - other.0
24614    }
24615}
24616
24617trait RowRangeExt {
24618    type Row;
24619
24620    fn len(&self) -> usize;
24621
24622    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
24623}
24624
24625impl RowRangeExt for Range<MultiBufferRow> {
24626    type Row = MultiBufferRow;
24627
24628    fn len(&self) -> usize {
24629        (self.end.0 - self.start.0) as usize
24630    }
24631
24632    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
24633        (self.start.0..self.end.0).map(MultiBufferRow)
24634    }
24635}
24636
24637impl RowRangeExt for Range<DisplayRow> {
24638    type Row = DisplayRow;
24639
24640    fn len(&self) -> usize {
24641        (self.end.0 - self.start.0) as usize
24642    }
24643
24644    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
24645        (self.start.0..self.end.0).map(DisplayRow)
24646    }
24647}
24648
24649/// If select range has more than one line, we
24650/// just point the cursor to range.start.
24651fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
24652    if range.start.row == range.end.row {
24653        range
24654    } else {
24655        range.start..range.start
24656    }
24657}
24658pub struct KillRing(ClipboardItem);
24659impl Global for KillRing {}
24660
24661const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
24662
24663enum BreakpointPromptEditAction {
24664    Log,
24665    Condition,
24666    HitCondition,
24667}
24668
24669struct BreakpointPromptEditor {
24670    pub(crate) prompt: Entity<Editor>,
24671    editor: WeakEntity<Editor>,
24672    breakpoint_anchor: Anchor,
24673    breakpoint: Breakpoint,
24674    edit_action: BreakpointPromptEditAction,
24675    block_ids: HashSet<CustomBlockId>,
24676    editor_margins: Arc<Mutex<EditorMargins>>,
24677    _subscriptions: Vec<Subscription>,
24678}
24679
24680impl BreakpointPromptEditor {
24681    const MAX_LINES: u8 = 4;
24682
24683    fn new(
24684        editor: WeakEntity<Editor>,
24685        breakpoint_anchor: Anchor,
24686        breakpoint: Breakpoint,
24687        edit_action: BreakpointPromptEditAction,
24688        window: &mut Window,
24689        cx: &mut Context<Self>,
24690    ) -> Self {
24691        let base_text = match edit_action {
24692            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
24693            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
24694            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
24695        }
24696        .map(|msg| msg.to_string())
24697        .unwrap_or_default();
24698
24699        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
24700        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
24701
24702        let prompt = cx.new(|cx| {
24703            let mut prompt = Editor::new(
24704                EditorMode::AutoHeight {
24705                    min_lines: 1,
24706                    max_lines: Some(Self::MAX_LINES as usize),
24707                },
24708                buffer,
24709                None,
24710                window,
24711                cx,
24712            );
24713            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
24714            prompt.set_show_cursor_when_unfocused(false, cx);
24715            prompt.set_placeholder_text(
24716                match edit_action {
24717                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
24718                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
24719                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
24720                },
24721                window,
24722                cx,
24723            );
24724
24725            prompt
24726        });
24727
24728        Self {
24729            prompt,
24730            editor,
24731            breakpoint_anchor,
24732            breakpoint,
24733            edit_action,
24734            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
24735            block_ids: Default::default(),
24736            _subscriptions: vec![],
24737        }
24738    }
24739
24740    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
24741        self.block_ids.extend(block_ids)
24742    }
24743
24744    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
24745        if let Some(editor) = self.editor.upgrade() {
24746            let message = self
24747                .prompt
24748                .read(cx)
24749                .buffer
24750                .read(cx)
24751                .as_singleton()
24752                .expect("A multi buffer in breakpoint prompt isn't possible")
24753                .read(cx)
24754                .as_rope()
24755                .to_string();
24756
24757            editor.update(cx, |editor, cx| {
24758                editor.edit_breakpoint_at_anchor(
24759                    self.breakpoint_anchor,
24760                    self.breakpoint.clone(),
24761                    match self.edit_action {
24762                        BreakpointPromptEditAction::Log => {
24763                            BreakpointEditAction::EditLogMessage(message.into())
24764                        }
24765                        BreakpointPromptEditAction::Condition => {
24766                            BreakpointEditAction::EditCondition(message.into())
24767                        }
24768                        BreakpointPromptEditAction::HitCondition => {
24769                            BreakpointEditAction::EditHitCondition(message.into())
24770                        }
24771                    },
24772                    cx,
24773                );
24774
24775                editor.remove_blocks(self.block_ids.clone(), None, cx);
24776                cx.focus_self(window);
24777            });
24778        }
24779    }
24780
24781    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
24782        self.editor
24783            .update(cx, |editor, cx| {
24784                editor.remove_blocks(self.block_ids.clone(), None, cx);
24785                window.focus(&editor.focus_handle);
24786            })
24787            .log_err();
24788    }
24789
24790    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
24791        let settings = ThemeSettings::get_global(cx);
24792        let text_style = TextStyle {
24793            color: if self.prompt.read(cx).read_only(cx) {
24794                cx.theme().colors().text_disabled
24795            } else {
24796                cx.theme().colors().text
24797            },
24798            font_family: settings.buffer_font.family.clone(),
24799            font_fallbacks: settings.buffer_font.fallbacks.clone(),
24800            font_size: settings.buffer_font_size(cx).into(),
24801            font_weight: settings.buffer_font.weight,
24802            line_height: relative(settings.buffer_line_height.value()),
24803            ..Default::default()
24804        };
24805        EditorElement::new(
24806            &self.prompt,
24807            EditorStyle {
24808                background: cx.theme().colors().editor_background,
24809                local_player: cx.theme().players().local(),
24810                text: text_style,
24811                ..Default::default()
24812            },
24813        )
24814    }
24815}
24816
24817impl Render for BreakpointPromptEditor {
24818    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
24819        let editor_margins = *self.editor_margins.lock();
24820        let gutter_dimensions = editor_margins.gutter;
24821        h_flex()
24822            .key_context("Editor")
24823            .bg(cx.theme().colors().editor_background)
24824            .border_y_1()
24825            .border_color(cx.theme().status().info_border)
24826            .size_full()
24827            .py(window.line_height() / 2.5)
24828            .on_action(cx.listener(Self::confirm))
24829            .on_action(cx.listener(Self::cancel))
24830            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
24831            .child(div().flex_1().child(self.render_prompt_editor(cx)))
24832    }
24833}
24834
24835impl Focusable for BreakpointPromptEditor {
24836    fn focus_handle(&self, cx: &App) -> FocusHandle {
24837        self.prompt.focus_handle(cx)
24838    }
24839}
24840
24841fn all_edits_insertions_or_deletions(
24842    edits: &Vec<(Range<Anchor>, Arc<str>)>,
24843    snapshot: &MultiBufferSnapshot,
24844) -> bool {
24845    let mut all_insertions = true;
24846    let mut all_deletions = true;
24847
24848    for (range, new_text) in edits.iter() {
24849        let range_is_empty = range.to_offset(snapshot).is_empty();
24850        let text_is_empty = new_text.is_empty();
24851
24852        if range_is_empty != text_is_empty {
24853            if range_is_empty {
24854                all_deletions = false;
24855            } else {
24856                all_insertions = false;
24857            }
24858        } else {
24859            return false;
24860        }
24861
24862        if !all_insertions && !all_deletions {
24863            return false;
24864        }
24865    }
24866    all_insertions || all_deletions
24867}
24868
24869struct MissingEditPredictionKeybindingTooltip;
24870
24871impl Render for MissingEditPredictionKeybindingTooltip {
24872    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
24873        ui::tooltip_container(cx, |container, cx| {
24874            container
24875                .flex_shrink_0()
24876                .max_w_80()
24877                .min_h(rems_from_px(124.))
24878                .justify_between()
24879                .child(
24880                    v_flex()
24881                        .flex_1()
24882                        .text_ui_sm(cx)
24883                        .child(Label::new("Conflict with Accept Keybinding"))
24884                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
24885                )
24886                .child(
24887                    h_flex()
24888                        .pb_1()
24889                        .gap_1()
24890                        .items_end()
24891                        .w_full()
24892                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
24893                            window.dispatch_action(zed_actions::OpenKeymapFile.boxed_clone(), cx)
24894                        }))
24895                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
24896                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
24897                        })),
24898                )
24899        })
24900    }
24901}
24902
24903#[derive(Debug, Clone, Copy, PartialEq)]
24904pub struct LineHighlight {
24905    pub background: Background,
24906    pub border: Option<gpui::Hsla>,
24907    pub include_gutter: bool,
24908    pub type_id: Option<TypeId>,
24909}
24910
24911struct LineManipulationResult {
24912    pub new_text: String,
24913    pub line_count_before: usize,
24914    pub line_count_after: usize,
24915}
24916
24917fn render_diff_hunk_controls(
24918    row: u32,
24919    status: &DiffHunkStatus,
24920    hunk_range: Range<Anchor>,
24921    is_created_file: bool,
24922    line_height: Pixels,
24923    editor: &Entity<Editor>,
24924    _window: &mut Window,
24925    cx: &mut App,
24926) -> AnyElement {
24927    h_flex()
24928        .h(line_height)
24929        .mr_1()
24930        .gap_1()
24931        .px_0p5()
24932        .pb_1()
24933        .border_x_1()
24934        .border_b_1()
24935        .border_color(cx.theme().colors().border_variant)
24936        .rounded_b_lg()
24937        .bg(cx.theme().colors().editor_background)
24938        .gap_1()
24939        .block_mouse_except_scroll()
24940        .shadow_md()
24941        .child(if status.has_secondary_hunk() {
24942            Button::new(("stage", row as u64), "Stage")
24943                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
24944                .tooltip({
24945                    let focus_handle = editor.focus_handle(cx);
24946                    move |_window, cx| {
24947                        Tooltip::for_action_in(
24948                            "Stage Hunk",
24949                            &::git::ToggleStaged,
24950                            &focus_handle,
24951                            cx,
24952                        )
24953                    }
24954                })
24955                .on_click({
24956                    let editor = editor.clone();
24957                    move |_event, _window, cx| {
24958                        editor.update(cx, |editor, cx| {
24959                            editor.stage_or_unstage_diff_hunks(
24960                                true,
24961                                vec![hunk_range.start..hunk_range.start],
24962                                cx,
24963                            );
24964                        });
24965                    }
24966                })
24967        } else {
24968            Button::new(("unstage", row as u64), "Unstage")
24969                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
24970                .tooltip({
24971                    let focus_handle = editor.focus_handle(cx);
24972                    move |_window, cx| {
24973                        Tooltip::for_action_in(
24974                            "Unstage Hunk",
24975                            &::git::ToggleStaged,
24976                            &focus_handle,
24977                            cx,
24978                        )
24979                    }
24980                })
24981                .on_click({
24982                    let editor = editor.clone();
24983                    move |_event, _window, cx| {
24984                        editor.update(cx, |editor, cx| {
24985                            editor.stage_or_unstage_diff_hunks(
24986                                false,
24987                                vec![hunk_range.start..hunk_range.start],
24988                                cx,
24989                            );
24990                        });
24991                    }
24992                })
24993        })
24994        .child(
24995            Button::new(("restore", row as u64), "Restore")
24996                .tooltip({
24997                    let focus_handle = editor.focus_handle(cx);
24998                    move |_window, cx| {
24999                        Tooltip::for_action_in("Restore Hunk", &::git::Restore, &focus_handle, cx)
25000                    }
25001                })
25002                .on_click({
25003                    let editor = editor.clone();
25004                    move |_event, window, cx| {
25005                        editor.update(cx, |editor, cx| {
25006                            let snapshot = editor.snapshot(window, cx);
25007                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot());
25008                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
25009                        });
25010                    }
25011                })
25012                .disabled(is_created_file),
25013        )
25014        .when(
25015            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
25016            |el| {
25017                el.child(
25018                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
25019                        .shape(IconButtonShape::Square)
25020                        .icon_size(IconSize::Small)
25021                        // .disabled(!has_multiple_hunks)
25022                        .tooltip({
25023                            let focus_handle = editor.focus_handle(cx);
25024                            move |_window, cx| {
25025                                Tooltip::for_action_in("Next Hunk", &GoToHunk, &focus_handle, cx)
25026                            }
25027                        })
25028                        .on_click({
25029                            let editor = editor.clone();
25030                            move |_event, window, cx| {
25031                                editor.update(cx, |editor, cx| {
25032                                    let snapshot = editor.snapshot(window, cx);
25033                                    let position =
25034                                        hunk_range.end.to_point(&snapshot.buffer_snapshot());
25035                                    editor.go_to_hunk_before_or_after_position(
25036                                        &snapshot,
25037                                        position,
25038                                        Direction::Next,
25039                                        window,
25040                                        cx,
25041                                    );
25042                                    editor.expand_selected_diff_hunks(cx);
25043                                });
25044                            }
25045                        }),
25046                )
25047                .child(
25048                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
25049                        .shape(IconButtonShape::Square)
25050                        .icon_size(IconSize::Small)
25051                        // .disabled(!has_multiple_hunks)
25052                        .tooltip({
25053                            let focus_handle = editor.focus_handle(cx);
25054                            move |_window, cx| {
25055                                Tooltip::for_action_in(
25056                                    "Previous Hunk",
25057                                    &GoToPreviousHunk,
25058                                    &focus_handle,
25059                                    cx,
25060                                )
25061                            }
25062                        })
25063                        .on_click({
25064                            let editor = editor.clone();
25065                            move |_event, window, cx| {
25066                                editor.update(cx, |editor, cx| {
25067                                    let snapshot = editor.snapshot(window, cx);
25068                                    let point =
25069                                        hunk_range.start.to_point(&snapshot.buffer_snapshot());
25070                                    editor.go_to_hunk_before_or_after_position(
25071                                        &snapshot,
25072                                        point,
25073                                        Direction::Prev,
25074                                        window,
25075                                        cx,
25076                                    );
25077                                    editor.expand_selected_diff_hunks(cx);
25078                                });
25079                            }
25080                        }),
25081                )
25082            },
25083        )
25084        .into_any_element()
25085}
25086
25087pub fn multibuffer_context_lines(cx: &App) -> u32 {
25088    EditorSettings::try_get(cx)
25089        .map(|settings| settings.excerpt_context_lines)
25090        .unwrap_or(2)
25091        .min(32)
25092}