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, BufferOffset, ExcerptId, ExcerptRange, MBTextSummary, MultiBuffer,
   68    MultiBufferOffset, MultiBufferOffsetUtf16, MultiBufferSnapshot, PathKey, RowInfo, ToOffset,
   69    ToPoint,
   70};
   71pub use text::Bias;
   72
   73use ::git::{
   74    Restore,
   75    blame::{BlameEntry, ParsedCommitMessage},
   76    status::FileStatus,
   77};
   78use aho_corasick::{AhoCorasick, AhoCorasickBuilder, BuildError};
   79use anyhow::{Context as _, Result, anyhow};
   80use blink_manager::BlinkManager;
   81use buffer_diff::DiffHunkStatus;
   82use client::{Collaborator, ParticipantIndex, parse_zed_link};
   83use clock::ReplicaId;
   84use code_context_menus::{
   85    AvailableCodeAction, CodeActionContents, CodeActionsItem, CodeActionsMenu, CodeContextMenu,
   86    CompletionsMenu, ContextMenuOrigin,
   87};
   88use collections::{BTreeMap, HashMap, HashSet, VecDeque};
   89use convert_case::{Case, Casing};
   90use dap::TelemetrySpawnLocation;
   91use display_map::*;
   92use edit_prediction::{EditPredictionProvider, EditPredictionProviderHandle};
   93use editor_settings::{GoToDefinitionFallback, Minimap as MinimapSettings};
   94use element::{AcceptEditPredictionBinding, LineWithInvisibles, PositionMap, layout_line};
   95use futures::{
   96    FutureExt, StreamExt as _,
   97    future::{self, Shared, join},
   98    stream::FuturesUnordered,
   99};
  100use fuzzy::{StringMatch, StringMatchCandidate};
  101use git::blame::{GitBlame, GlobalBlameRenderer};
  102use gpui::{
  103    Action, Animation, AnimationExt, AnyElement, App, AppContext, AsyncWindowContext,
  104    AvailableSpace, Background, Bounds, ClickEvent, ClipboardEntry, ClipboardItem, Context,
  105    DispatchPhase, Edges, Entity, EntityInputHandler, EventEmitter, FocusHandle, FocusOutEvent,
  106    Focusable, FontId, FontWeight, Global, HighlightStyle, Hsla, KeyContext, Modifiers,
  107    MouseButton, MouseDownEvent, PaintQuad, ParentElement, Pixels, Render, ScrollHandle,
  108    SharedString, Size, Stateful, Styled, Subscription, Task, TextStyle, TextStyleRefinement,
  109    UTF16Selection, UnderlineStyle, UniformListScrollHandle, WeakEntity, WeakFocusHandle, Window,
  110    div, point, prelude::*, pulsating_between, px, relative, size,
  111};
  112use hover_links::{HoverLink, HoveredLinkState, find_file};
  113use hover_popover::{HoverState, hide_hover};
  114use indent_guides::ActiveIndentGuidesState;
  115use inlays::{InlaySplice, inlay_hints::InlayHintRefreshReason};
  116use itertools::{Either, Itertools};
  117use language::{
  118    AutoindentMode, BlockCommentConfig, BracketMatch, BracketPair, Buffer, BufferRow,
  119    BufferSnapshot, Capability, CharClassifier, CharKind, CharScopeContext, CodeLabel, CursorShape,
  120    DiagnosticEntryRef, DiffOptions, EditPredictionsMode, EditPreview, HighlightedText, IndentKind,
  121    IndentSize, Language, LanguageRegistry, OffsetRangeExt, OutlineItem, Point, Runnable,
  122    Selection, SelectionGoal, TextObject, TransactionId, TreeSitterOptions, WordsQuery,
  123    language_settings::{
  124        self, LspInsertMode, RewrapBehavior, WordsCompletionMode, all_language_settings,
  125        language_settings,
  126    },
  127    point_from_lsp, point_to_lsp, text_diff_with_options,
  128};
  129use linked_editing_ranges::refresh_linked_ranges;
  130use lsp::{
  131    CodeActionKind, CompletionItemKind, CompletionTriggerKind, InsertTextFormat, InsertTextMode,
  132    LanguageServerId,
  133};
  134use lsp_colors::LspColorData;
  135use markdown::Markdown;
  136use mouse_context_menu::MouseContextMenu;
  137use movement::TextLayoutDetails;
  138use multi_buffer::{
  139    ExcerptInfo, ExpandExcerptDirection, MultiBufferDiffHunk, MultiBufferPoint, MultiBufferRow,
  140};
  141use parking_lot::Mutex;
  142use persistence::DB;
  143use project::{
  144    BreakpointWithPosition, CodeAction, Completion, CompletionDisplayOptions, CompletionIntent,
  145    CompletionResponse, CompletionSource, DisableAiSettings, DocumentHighlight, InlayHint, InlayId,
  146    InvalidationStrategy, Location, LocationLink, PrepareRenameResponse, Project, ProjectItem,
  147    ProjectPath, ProjectTransaction, TaskSourceKind,
  148    debugger::{
  149        breakpoint_store::{
  150            Breakpoint, BreakpointEditAction, BreakpointSessionState, BreakpointState,
  151            BreakpointStore, BreakpointStoreEvent,
  152        },
  153        session::{Session, SessionEvent},
  154    },
  155    git_store::GitStoreEvent,
  156    lsp_store::{
  157        CacheInlayHints, CompletionDocumentation, FormatTrigger, LspFormatTarget,
  158        OpenLspBufferHandle,
  159    },
  160    project_settings::{DiagnosticSeverity, GoToDiagnosticSeverityFilter, ProjectSettings},
  161};
  162use rand::seq::SliceRandom;
  163use rpc::{ErrorCode, ErrorExt, proto::PeerId};
  164use scroll::{Autoscroll, OngoingScroll, ScrollAnchor, ScrollManager};
  165use selections_collection::{MutableSelectionsCollection, SelectionsCollection};
  166use serde::{Deserialize, Serialize};
  167use settings::{
  168    GitGutterSetting, RelativeLineNumbers, Settings, SettingsLocation, SettingsStore,
  169    update_settings_file,
  170};
  171use smallvec::{SmallVec, smallvec};
  172use snippet::Snippet;
  173use std::{
  174    any::{Any, TypeId},
  175    borrow::Cow,
  176    cell::{OnceCell, RefCell},
  177    cmp::{self, Ordering, Reverse},
  178    iter::{self, Peekable},
  179    mem,
  180    num::NonZeroU32,
  181    ops::{Deref, DerefMut, Not, Range, RangeInclusive},
  182    path::{Path, PathBuf},
  183    rc::Rc,
  184    sync::Arc,
  185    time::{Duration, Instant},
  186};
  187use task::{ResolvedTask, RunnableTag, TaskTemplate, TaskVariables};
  188use text::{BufferId, FromAnchor, OffsetUtf16, Rope, ToOffset as _};
  189use theme::{
  190    ActiveTheme, PlayerColor, StatusColors, SyntaxTheme, Theme, ThemeSettings,
  191    observe_buffer_font_size_adjustment,
  192};
  193use ui::{
  194    ButtonSize, ButtonStyle, ContextMenu, Disclosure, IconButton, IconButtonShape, IconName,
  195    IconSize, Indicator, Key, Tooltip, h_flex, prelude::*, scrollbars::ScrollbarAutoHide,
  196};
  197use util::{RangeExt, ResultExt, TryFutureExt, maybe, post_inc};
  198use workspace::{
  199    CollaboratorId, Item as WorkspaceItem, ItemId, ItemNavHistory, OpenInTerminal, OpenTerminal,
  200    RestoreOnStartupBehavior, SERIALIZATION_THROTTLE_TIME, SplitDirection, TabBarSettings, Toast,
  201    ViewId, Workspace, WorkspaceId, WorkspaceSettings,
  202    item::{ItemBufferKind, ItemHandle, PreviewTabsSettings, SaveOptions},
  203    notifications::{DetachAndPromptErr, NotificationId, NotifyTaskExt},
  204    searchable::SearchEvent,
  205};
  206
  207use crate::{
  208    code_context_menus::CompletionsMenuSource,
  209    editor_settings::MultiCursorModifier,
  210    hover_links::{find_url, find_url_from_range},
  211    inlays::{
  212        InlineValueCache,
  213        inlay_hints::{LspInlayHintData, inlay_hint_settings},
  214    },
  215    scroll::{ScrollOffset, ScrollPixelOffset},
  216    selections_collection::resolve_selections_wrapping_blocks,
  217    signature_help::{SignatureHelpHiddenBy, SignatureHelpState},
  218};
  219
  220pub const FILE_HEADER_HEIGHT: u32 = 2;
  221pub const MULTI_BUFFER_EXCERPT_HEADER_HEIGHT: u32 = 1;
  222const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500);
  223const MAX_LINE_LEN: usize = 1024;
  224const MIN_NAVIGATION_HISTORY_ROW_DELTA: i64 = 10;
  225const MAX_SELECTION_HISTORY_LEN: usize = 1024;
  226pub(crate) const CURSORS_VISIBLE_FOR: Duration = Duration::from_millis(2000);
  227#[doc(hidden)]
  228pub const CODE_ACTIONS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(250);
  229pub const SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(100);
  230
  231pub(crate) const CODE_ACTION_TIMEOUT: Duration = Duration::from_secs(5);
  232pub(crate) const FORMAT_TIMEOUT: Duration = Duration::from_secs(5);
  233pub(crate) const SCROLL_CENTER_TOP_BOTTOM_DEBOUNCE_TIMEOUT: Duration = Duration::from_secs(1);
  234pub const FETCH_COLORS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(150);
  235
  236pub(crate) const EDIT_PREDICTION_KEY_CONTEXT: &str = "edit_prediction";
  237pub(crate) const EDIT_PREDICTION_CONFLICT_KEY_CONTEXT: &str = "edit_prediction_conflict";
  238pub(crate) const MINIMAP_FONT_SIZE: AbsoluteLength = AbsoluteLength::Pixels(px(2.));
  239
  240pub type RenderDiffHunkControlsFn = Arc<
  241    dyn Fn(
  242        u32,
  243        &DiffHunkStatus,
  244        Range<Anchor>,
  245        bool,
  246        Pixels,
  247        &Entity<Editor>,
  248        &mut Window,
  249        &mut App,
  250    ) -> AnyElement,
  251>;
  252
  253enum ReportEditorEvent {
  254    Saved { auto_saved: bool },
  255    EditorOpened,
  256    Closed,
  257}
  258
  259impl ReportEditorEvent {
  260    pub fn event_type(&self) -> &'static str {
  261        match self {
  262            Self::Saved { .. } => "Editor Saved",
  263            Self::EditorOpened => "Editor Opened",
  264            Self::Closed => "Editor Closed",
  265        }
  266    }
  267}
  268
  269pub enum ActiveDebugLine {}
  270pub enum DebugStackFrameLine {}
  271enum DocumentHighlightRead {}
  272enum DocumentHighlightWrite {}
  273enum InputComposition {}
  274pub enum PendingInput {}
  275enum SelectedTextHighlight {}
  276
  277pub enum ConflictsOuter {}
  278pub enum ConflictsOurs {}
  279pub enum ConflictsTheirs {}
  280pub enum ConflictsOursMarker {}
  281pub enum ConflictsTheirsMarker {}
  282
  283#[derive(Debug, Copy, Clone, PartialEq, Eq)]
  284pub enum Navigated {
  285    Yes,
  286    No,
  287}
  288
  289impl Navigated {
  290    pub fn from_bool(yes: bool) -> Navigated {
  291        if yes { Navigated::Yes } else { Navigated::No }
  292    }
  293}
  294
  295#[derive(Debug, Clone, PartialEq, Eq)]
  296enum DisplayDiffHunk {
  297    Folded {
  298        display_row: DisplayRow,
  299    },
  300    Unfolded {
  301        is_created_file: bool,
  302        diff_base_byte_range: Range<usize>,
  303        display_row_range: Range<DisplayRow>,
  304        multi_buffer_range: Range<Anchor>,
  305        status: DiffHunkStatus,
  306    },
  307}
  308
  309pub enum HideMouseCursorOrigin {
  310    TypingAction,
  311    MovementAction,
  312}
  313
  314pub fn init(cx: &mut App) {
  315    cx.set_global(GlobalBlameRenderer(Arc::new(())));
  316
  317    workspace::register_project_item::<Editor>(cx);
  318    workspace::FollowableViewRegistry::register::<Editor>(cx);
  319    workspace::register_serializable_item::<Editor>(cx);
  320
  321    cx.observe_new(
  322        |workspace: &mut Workspace, _: Option<&mut Window>, _cx: &mut Context<Workspace>| {
  323            workspace.register_action(Editor::new_file);
  324            workspace.register_action(Editor::new_file_split);
  325            workspace.register_action(Editor::new_file_vertical);
  326            workspace.register_action(Editor::new_file_horizontal);
  327            workspace.register_action(Editor::cancel_language_server_work);
  328            workspace.register_action(Editor::toggle_focus);
  329        },
  330    )
  331    .detach();
  332
  333    cx.on_action(move |_: &workspace::NewFile, cx| {
  334        let app_state = workspace::AppState::global(cx);
  335        if let Some(app_state) = app_state.upgrade() {
  336            workspace::open_new(
  337                Default::default(),
  338                app_state,
  339                cx,
  340                |workspace, window, cx| {
  341                    Editor::new_file(workspace, &Default::default(), window, cx)
  342                },
  343            )
  344            .detach();
  345        }
  346    });
  347    cx.on_action(move |_: &workspace::NewWindow, cx| {
  348        let app_state = workspace::AppState::global(cx);
  349        if let Some(app_state) = app_state.upgrade() {
  350            workspace::open_new(
  351                Default::default(),
  352                app_state,
  353                cx,
  354                |workspace, window, cx| {
  355                    cx.activate(true);
  356                    Editor::new_file(workspace, &Default::default(), window, cx)
  357                },
  358            )
  359            .detach();
  360        }
  361    });
  362}
  363
  364pub fn set_blame_renderer(renderer: impl BlameRenderer + 'static, cx: &mut App) {
  365    cx.set_global(GlobalBlameRenderer(Arc::new(renderer)));
  366}
  367
  368pub trait DiagnosticRenderer {
  369    fn render_group(
  370        &self,
  371        diagnostic_group: Vec<DiagnosticEntryRef<'_, Point>>,
  372        buffer_id: BufferId,
  373        snapshot: EditorSnapshot,
  374        editor: WeakEntity<Editor>,
  375        language_registry: Option<Arc<LanguageRegistry>>,
  376        cx: &mut App,
  377    ) -> Vec<BlockProperties<Anchor>>;
  378
  379    fn render_hover(
  380        &self,
  381        diagnostic_group: Vec<DiagnosticEntryRef<'_, Point>>,
  382        range: Range<Point>,
  383        buffer_id: BufferId,
  384        language_registry: Option<Arc<LanguageRegistry>>,
  385        cx: &mut App,
  386    ) -> Option<Entity<markdown::Markdown>>;
  387
  388    fn open_link(
  389        &self,
  390        editor: &mut Editor,
  391        link: SharedString,
  392        window: &mut Window,
  393        cx: &mut Context<Editor>,
  394    );
  395}
  396
  397pub(crate) struct GlobalDiagnosticRenderer(pub Arc<dyn DiagnosticRenderer>);
  398
  399impl GlobalDiagnosticRenderer {
  400    fn global(cx: &App) -> Option<Arc<dyn DiagnosticRenderer>> {
  401        cx.try_global::<Self>().map(|g| g.0.clone())
  402    }
  403}
  404
  405impl gpui::Global for GlobalDiagnosticRenderer {}
  406pub fn set_diagnostic_renderer(renderer: impl DiagnosticRenderer + 'static, cx: &mut App) {
  407    cx.set_global(GlobalDiagnosticRenderer(Arc::new(renderer)));
  408}
  409
  410pub struct SearchWithinRange;
  411
  412trait InvalidationRegion {
  413    fn ranges(&self) -> &[Range<Anchor>];
  414}
  415
  416#[derive(Clone, Debug, PartialEq)]
  417pub enum SelectPhase {
  418    Begin {
  419        position: DisplayPoint,
  420        add: bool,
  421        click_count: usize,
  422    },
  423    BeginColumnar {
  424        position: DisplayPoint,
  425        reset: bool,
  426        mode: ColumnarMode,
  427        goal_column: u32,
  428    },
  429    Extend {
  430        position: DisplayPoint,
  431        click_count: usize,
  432    },
  433    Update {
  434        position: DisplayPoint,
  435        goal_column: u32,
  436        scroll_delta: gpui::Point<f32>,
  437    },
  438    End,
  439}
  440
  441#[derive(Clone, Debug, PartialEq)]
  442pub enum ColumnarMode {
  443    FromMouse,
  444    FromSelection,
  445}
  446
  447#[derive(Clone, Debug)]
  448pub enum SelectMode {
  449    Character,
  450    Word(Range<Anchor>),
  451    Line(Range<Anchor>),
  452    All,
  453}
  454
  455#[derive(Copy, Clone, Default, PartialEq, Eq, Debug)]
  456pub enum SizingBehavior {
  457    /// The editor will layout itself using `size_full` and will include the vertical
  458    /// scroll margin as requested by user settings.
  459    #[default]
  460    Default,
  461    /// The editor will layout itself using `size_full`, but will not have any
  462    /// vertical overscroll.
  463    ExcludeOverscrollMargin,
  464    /// The editor will request a vertical size according to its content and will be
  465    /// layouted without a vertical scroll margin.
  466    SizeByContent,
  467}
  468
  469#[derive(Clone, PartialEq, Eq, Debug)]
  470pub enum EditorMode {
  471    SingleLine,
  472    AutoHeight {
  473        min_lines: usize,
  474        max_lines: Option<usize>,
  475    },
  476    Full {
  477        /// When set to `true`, the editor will scale its UI elements with the buffer font size.
  478        scale_ui_elements_with_buffer_font_size: bool,
  479        /// When set to `true`, the editor will render a background for the active line.
  480        show_active_line_background: bool,
  481        /// Determines the sizing behavior for this editor
  482        sizing_behavior: SizingBehavior,
  483    },
  484    Minimap {
  485        parent: WeakEntity<Editor>,
  486    },
  487}
  488
  489impl EditorMode {
  490    pub fn full() -> Self {
  491        Self::Full {
  492            scale_ui_elements_with_buffer_font_size: true,
  493            show_active_line_background: true,
  494            sizing_behavior: SizingBehavior::Default,
  495        }
  496    }
  497
  498    #[inline]
  499    pub fn is_full(&self) -> bool {
  500        matches!(self, Self::Full { .. })
  501    }
  502
  503    #[inline]
  504    pub fn is_single_line(&self) -> bool {
  505        matches!(self, Self::SingleLine { .. })
  506    }
  507
  508    #[inline]
  509    fn is_minimap(&self) -> bool {
  510        matches!(self, Self::Minimap { .. })
  511    }
  512}
  513
  514#[derive(Copy, Clone, Debug)]
  515pub enum SoftWrap {
  516    /// Prefer not to wrap at all.
  517    ///
  518    /// Note: this is currently internal, as actually limited by [`crate::MAX_LINE_LEN`] until it wraps.
  519    /// The mode is used inside git diff hunks, where it's seems currently more useful to not wrap as much as possible.
  520    GitDiff,
  521    /// Prefer a single line generally, unless an overly long line is encountered.
  522    None,
  523    /// Soft wrap lines that exceed the editor width.
  524    EditorWidth,
  525    /// Soft wrap lines at the preferred line length.
  526    Column(u32),
  527    /// Soft wrap line at the preferred line length or the editor width (whichever is smaller).
  528    Bounded(u32),
  529}
  530
  531#[derive(Clone)]
  532pub struct EditorStyle {
  533    pub background: Hsla,
  534    pub border: Hsla,
  535    pub local_player: PlayerColor,
  536    pub text: TextStyle,
  537    pub scrollbar_width: Pixels,
  538    pub syntax: Arc<SyntaxTheme>,
  539    pub status: StatusColors,
  540    pub inlay_hints_style: HighlightStyle,
  541    pub edit_prediction_styles: EditPredictionStyles,
  542    pub unnecessary_code_fade: f32,
  543    pub show_underlines: bool,
  544}
  545
  546impl Default for EditorStyle {
  547    fn default() -> Self {
  548        Self {
  549            background: Hsla::default(),
  550            border: Hsla::default(),
  551            local_player: PlayerColor::default(),
  552            text: TextStyle::default(),
  553            scrollbar_width: Pixels::default(),
  554            syntax: Default::default(),
  555            // HACK: Status colors don't have a real default.
  556            // We should look into removing the status colors from the editor
  557            // style and retrieve them directly from the theme.
  558            status: StatusColors::dark(),
  559            inlay_hints_style: HighlightStyle::default(),
  560            edit_prediction_styles: EditPredictionStyles {
  561                insertion: HighlightStyle::default(),
  562                whitespace: HighlightStyle::default(),
  563            },
  564            unnecessary_code_fade: Default::default(),
  565            show_underlines: true,
  566        }
  567    }
  568}
  569
  570pub fn make_inlay_hints_style(cx: &mut App) -> HighlightStyle {
  571    let show_background = language_settings::language_settings(None, None, cx)
  572        .inlay_hints
  573        .show_background;
  574
  575    let mut style = cx.theme().syntax().get("hint");
  576
  577    if style.color.is_none() {
  578        style.color = Some(cx.theme().status().hint);
  579    }
  580
  581    if !show_background {
  582        style.background_color = None;
  583        return style;
  584    }
  585
  586    if style.background_color.is_none() {
  587        style.background_color = Some(cx.theme().status().hint_background);
  588    }
  589
  590    style
  591}
  592
  593pub fn make_suggestion_styles(cx: &mut App) -> EditPredictionStyles {
  594    EditPredictionStyles {
  595        insertion: HighlightStyle {
  596            color: Some(cx.theme().status().predictive),
  597            ..HighlightStyle::default()
  598        },
  599        whitespace: HighlightStyle {
  600            background_color: Some(cx.theme().status().created_background),
  601            ..HighlightStyle::default()
  602        },
  603    }
  604}
  605
  606type CompletionId = usize;
  607
  608pub(crate) enum EditDisplayMode {
  609    TabAccept,
  610    DiffPopover,
  611    Inline,
  612}
  613
  614enum EditPrediction {
  615    Edit {
  616        edits: Vec<(Range<Anchor>, Arc<str>)>,
  617        edit_preview: Option<EditPreview>,
  618        display_mode: EditDisplayMode,
  619        snapshot: BufferSnapshot,
  620    },
  621    /// Move to a specific location in the active editor
  622    MoveWithin {
  623        target: Anchor,
  624        snapshot: BufferSnapshot,
  625    },
  626    /// Move to a specific location in a different editor (not the active one)
  627    MoveOutside {
  628        target: language::Anchor,
  629        snapshot: BufferSnapshot,
  630    },
  631}
  632
  633struct EditPredictionState {
  634    inlay_ids: Vec<InlayId>,
  635    completion: EditPrediction,
  636    completion_id: Option<SharedString>,
  637    invalidation_range: Option<Range<Anchor>>,
  638}
  639
  640enum EditPredictionSettings {
  641    Disabled,
  642    Enabled {
  643        show_in_menu: bool,
  644        preview_requires_modifier: bool,
  645    },
  646}
  647
  648enum EditPredictionHighlight {}
  649
  650#[derive(Debug, Clone)]
  651struct InlineDiagnostic {
  652    message: SharedString,
  653    group_id: usize,
  654    is_primary: bool,
  655    start: Point,
  656    severity: lsp::DiagnosticSeverity,
  657}
  658
  659pub enum MenuEditPredictionsPolicy {
  660    Never,
  661    ByProvider,
  662}
  663
  664pub enum EditPredictionPreview {
  665    /// Modifier is not pressed
  666    Inactive { released_too_fast: bool },
  667    /// Modifier pressed
  668    Active {
  669        since: Instant,
  670        previous_scroll_position: Option<ScrollAnchor>,
  671    },
  672}
  673
  674impl EditPredictionPreview {
  675    pub fn released_too_fast(&self) -> bool {
  676        match self {
  677            EditPredictionPreview::Inactive { released_too_fast } => *released_too_fast,
  678            EditPredictionPreview::Active { .. } => false,
  679        }
  680    }
  681
  682    pub fn set_previous_scroll_position(&mut self, scroll_position: Option<ScrollAnchor>) {
  683        if let EditPredictionPreview::Active {
  684            previous_scroll_position,
  685            ..
  686        } = self
  687        {
  688            *previous_scroll_position = scroll_position;
  689        }
  690    }
  691}
  692
  693pub struct ContextMenuOptions {
  694    pub min_entries_visible: usize,
  695    pub max_entries_visible: usize,
  696    pub placement: Option<ContextMenuPlacement>,
  697}
  698
  699#[derive(Debug, Clone, PartialEq, Eq)]
  700pub enum ContextMenuPlacement {
  701    Above,
  702    Below,
  703}
  704
  705#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug, Default)]
  706struct EditorActionId(usize);
  707
  708impl EditorActionId {
  709    pub fn post_inc(&mut self) -> Self {
  710        let answer = self.0;
  711
  712        *self = Self(answer + 1);
  713
  714        Self(answer)
  715    }
  716}
  717
  718// type GetFieldEditorTheme = dyn Fn(&theme::Theme) -> theme::FieldEditor;
  719// type OverrideTextStyle = dyn Fn(&EditorStyle) -> Option<HighlightStyle>;
  720
  721type BackgroundHighlight = (fn(&Theme) -> Hsla, Arc<[Range<Anchor>]>);
  722type GutterHighlight = (fn(&App) -> Hsla, Vec<Range<Anchor>>);
  723
  724#[derive(Default)]
  725struct ScrollbarMarkerState {
  726    scrollbar_size: Size<Pixels>,
  727    dirty: bool,
  728    markers: Arc<[PaintQuad]>,
  729    pending_refresh: Option<Task<Result<()>>>,
  730}
  731
  732impl ScrollbarMarkerState {
  733    fn should_refresh(&self, scrollbar_size: Size<Pixels>) -> bool {
  734        self.pending_refresh.is_none() && (self.scrollbar_size != scrollbar_size || self.dirty)
  735    }
  736}
  737
  738#[derive(Clone, Copy, PartialEq, Eq)]
  739pub enum MinimapVisibility {
  740    Disabled,
  741    Enabled {
  742        /// The configuration currently present in the users settings.
  743        setting_configuration: bool,
  744        /// Whether to override the currently set visibility from the users setting.
  745        toggle_override: bool,
  746    },
  747}
  748
  749impl MinimapVisibility {
  750    fn for_mode(mode: &EditorMode, cx: &App) -> Self {
  751        if mode.is_full() {
  752            Self::Enabled {
  753                setting_configuration: EditorSettings::get_global(cx).minimap.minimap_enabled(),
  754                toggle_override: false,
  755            }
  756        } else {
  757            Self::Disabled
  758        }
  759    }
  760
  761    fn hidden(&self) -> Self {
  762        match *self {
  763            Self::Enabled {
  764                setting_configuration,
  765                ..
  766            } => Self::Enabled {
  767                setting_configuration,
  768                toggle_override: setting_configuration,
  769            },
  770            Self::Disabled => Self::Disabled,
  771        }
  772    }
  773
  774    fn disabled(&self) -> bool {
  775        matches!(*self, Self::Disabled)
  776    }
  777
  778    fn settings_visibility(&self) -> bool {
  779        match *self {
  780            Self::Enabled {
  781                setting_configuration,
  782                ..
  783            } => setting_configuration,
  784            _ => false,
  785        }
  786    }
  787
  788    fn visible(&self) -> bool {
  789        match *self {
  790            Self::Enabled {
  791                setting_configuration,
  792                toggle_override,
  793            } => setting_configuration ^ toggle_override,
  794            _ => false,
  795        }
  796    }
  797
  798    fn toggle_visibility(&self) -> Self {
  799        match *self {
  800            Self::Enabled {
  801                toggle_override,
  802                setting_configuration,
  803            } => Self::Enabled {
  804                setting_configuration,
  805                toggle_override: !toggle_override,
  806            },
  807            Self::Disabled => Self::Disabled,
  808        }
  809    }
  810}
  811
  812#[derive(Debug, Clone, Copy, PartialEq, Eq)]
  813pub enum BufferSerialization {
  814    All,
  815    NonDirtyBuffers,
  816}
  817
  818impl BufferSerialization {
  819    fn new(restore_unsaved_buffers: bool) -> Self {
  820        if restore_unsaved_buffers {
  821            Self::All
  822        } else {
  823            Self::NonDirtyBuffers
  824        }
  825    }
  826}
  827
  828#[derive(Clone, Debug)]
  829struct RunnableTasks {
  830    templates: Vec<(TaskSourceKind, TaskTemplate)>,
  831    offset: multi_buffer::Anchor,
  832    // We need the column at which the task context evaluation should take place (when we're spawning it via gutter).
  833    column: u32,
  834    // Values of all named captures, including those starting with '_'
  835    extra_variables: HashMap<String, String>,
  836    // Full range of the tagged region. We use it to determine which `extra_variables` to grab for context resolution in e.g. a modal.
  837    context_range: Range<BufferOffset>,
  838}
  839
  840impl RunnableTasks {
  841    fn resolve<'a>(
  842        &'a self,
  843        cx: &'a task::TaskContext,
  844    ) -> impl Iterator<Item = (TaskSourceKind, ResolvedTask)> + 'a {
  845        self.templates.iter().filter_map(|(kind, template)| {
  846            template
  847                .resolve_task(&kind.to_id_base(), cx)
  848                .map(|task| (kind.clone(), task))
  849        })
  850    }
  851}
  852
  853#[derive(Clone)]
  854pub struct ResolvedTasks {
  855    templates: SmallVec<[(TaskSourceKind, ResolvedTask); 1]>,
  856    position: Anchor,
  857}
  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    pub collapse_matches: bool,
 1100    autoindent_mode: Option<AutoindentMode>,
 1101    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
 1102    input_enabled: bool,
 1103    use_modal_editing: bool,
 1104    read_only: bool,
 1105    leader_id: Option<CollaboratorId>,
 1106    remote_id: Option<ViewId>,
 1107    pub hover_state: HoverState,
 1108    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
 1109    gutter_hovered: bool,
 1110    hovered_link_state: Option<HoveredLinkState>,
 1111    edit_prediction_provider: Option<RegisteredEditPredictionProvider>,
 1112    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
 1113    active_edit_prediction: Option<EditPredictionState>,
 1114    /// Used to prevent flickering as the user types while the menu is open
 1115    stale_edit_prediction_in_menu: Option<EditPredictionState>,
 1116    edit_prediction_settings: EditPredictionSettings,
 1117    edit_predictions_hidden_for_vim_mode: bool,
 1118    show_edit_predictions_override: Option<bool>,
 1119    menu_edit_predictions_policy: MenuEditPredictionsPolicy,
 1120    edit_prediction_preview: EditPredictionPreview,
 1121    edit_prediction_indent_conflict: bool,
 1122    edit_prediction_requires_modifier_in_indent_conflict: bool,
 1123    next_inlay_id: usize,
 1124    next_color_inlay_id: usize,
 1125    _subscriptions: Vec<Subscription>,
 1126    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
 1127    gutter_dimensions: GutterDimensions,
 1128    style: Option<EditorStyle>,
 1129    text_style_refinement: Option<TextStyleRefinement>,
 1130    next_editor_action_id: EditorActionId,
 1131    editor_actions: Rc<
 1132        RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&Editor, &mut Window, &mut Context<Self>)>>>,
 1133    >,
 1134    use_autoclose: bool,
 1135    use_auto_surround: bool,
 1136    auto_replace_emoji_shortcode: bool,
 1137    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1138    show_git_blame_gutter: bool,
 1139    show_git_blame_inline: bool,
 1140    show_git_blame_inline_delay_task: Option<Task<()>>,
 1141    git_blame_inline_enabled: bool,
 1142    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1143    buffer_serialization: Option<BufferSerialization>,
 1144    show_selection_menu: Option<bool>,
 1145    blame: Option<Entity<GitBlame>>,
 1146    blame_subscription: Option<Subscription>,
 1147    custom_context_menu: Option<
 1148        Box<
 1149            dyn 'static
 1150                + Fn(
 1151                    &mut Self,
 1152                    DisplayPoint,
 1153                    &mut Window,
 1154                    &mut Context<Self>,
 1155                ) -> Option<Entity<ui::ContextMenu>>,
 1156        >,
 1157    >,
 1158    last_bounds: Option<Bounds<Pixels>>,
 1159    last_position_map: Option<Rc<PositionMap>>,
 1160    expect_bounds_change: Option<Bounds<Pixels>>,
 1161    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
 1162    tasks_update_task: Option<Task<()>>,
 1163    breakpoint_store: Option<Entity<BreakpointStore>>,
 1164    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1165    hovered_diff_hunk_row: Option<DisplayRow>,
 1166    pull_diagnostics_task: Task<()>,
 1167    in_project_search: bool,
 1168    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1169    breadcrumb_header: Option<String>,
 1170    focused_block: Option<FocusedBlock>,
 1171    next_scroll_position: NextScrollCursorCenterTopBottom,
 1172    addons: HashMap<TypeId, Box<dyn Addon>>,
 1173    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1174    load_diff_task: Option<Shared<Task<()>>>,
 1175    /// Whether we are temporarily displaying a diff other than git's
 1176    temporary_diff_override: bool,
 1177    selection_mark_mode: bool,
 1178    toggle_fold_multiple_buffers: Task<()>,
 1179    _scroll_cursor_center_top_bottom_task: Task<()>,
 1180    serialize_selections: Task<()>,
 1181    serialize_folds: Task<()>,
 1182    mouse_cursor_hidden: bool,
 1183    minimap: Option<Entity<Self>>,
 1184    hide_mouse_mode: HideMouseMode,
 1185    pub change_list: ChangeList,
 1186    inline_value_cache: InlineValueCache,
 1187
 1188    selection_drag_state: SelectionDragState,
 1189    colors: Option<LspColorData>,
 1190    post_scroll_update: Task<()>,
 1191    refresh_colors_task: Task<()>,
 1192    inlay_hints: Option<LspInlayHintData>,
 1193    folding_newlines: Task<()>,
 1194    select_next_is_case_sensitive: Option<bool>,
 1195    pub lookup_key: Option<Box<dyn Any + Send + Sync>>,
 1196}
 1197
 1198fn debounce_value(debounce_ms: u64) -> Option<Duration> {
 1199    if debounce_ms > 0 {
 1200        Some(Duration::from_millis(debounce_ms))
 1201    } else {
 1202        None
 1203    }
 1204}
 1205
 1206#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1207enum NextScrollCursorCenterTopBottom {
 1208    #[default]
 1209    Center,
 1210    Top,
 1211    Bottom,
 1212}
 1213
 1214impl NextScrollCursorCenterTopBottom {
 1215    fn next(&self) -> Self {
 1216        match self {
 1217            Self::Center => Self::Top,
 1218            Self::Top => Self::Bottom,
 1219            Self::Bottom => Self::Center,
 1220        }
 1221    }
 1222}
 1223
 1224#[derive(Clone)]
 1225pub struct EditorSnapshot {
 1226    pub mode: EditorMode,
 1227    show_gutter: bool,
 1228    show_line_numbers: Option<bool>,
 1229    show_git_diff_gutter: Option<bool>,
 1230    show_code_actions: Option<bool>,
 1231    show_runnables: Option<bool>,
 1232    show_breakpoints: Option<bool>,
 1233    git_blame_gutter_max_author_length: Option<usize>,
 1234    pub display_snapshot: DisplaySnapshot,
 1235    pub placeholder_display_snapshot: Option<DisplaySnapshot>,
 1236    is_focused: bool,
 1237    scroll_anchor: ScrollAnchor,
 1238    ongoing_scroll: OngoingScroll,
 1239    current_line_highlight: CurrentLineHighlight,
 1240    gutter_hovered: bool,
 1241}
 1242
 1243#[derive(Default, Debug, Clone, Copy)]
 1244pub struct GutterDimensions {
 1245    pub left_padding: Pixels,
 1246    pub right_padding: Pixels,
 1247    pub width: Pixels,
 1248    pub margin: Pixels,
 1249    pub git_blame_entries_width: Option<Pixels>,
 1250}
 1251
 1252impl GutterDimensions {
 1253    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1254        Self {
 1255            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1256            ..Default::default()
 1257        }
 1258    }
 1259
 1260    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1261        -cx.text_system().descent(font_id, font_size)
 1262    }
 1263    /// The full width of the space taken up by the gutter.
 1264    pub fn full_width(&self) -> Pixels {
 1265        self.margin + self.width
 1266    }
 1267
 1268    /// The width of the space reserved for the fold indicators,
 1269    /// use alongside 'justify_end' and `gutter_width` to
 1270    /// right align content with the line numbers
 1271    pub fn fold_area_width(&self) -> Pixels {
 1272        self.margin + self.right_padding
 1273    }
 1274}
 1275
 1276struct CharacterDimensions {
 1277    em_width: Pixels,
 1278    em_advance: Pixels,
 1279    line_height: Pixels,
 1280}
 1281
 1282#[derive(Debug)]
 1283pub struct RemoteSelection {
 1284    pub replica_id: ReplicaId,
 1285    pub selection: Selection<Anchor>,
 1286    pub cursor_shape: CursorShape,
 1287    pub collaborator_id: CollaboratorId,
 1288    pub line_mode: bool,
 1289    pub user_name: Option<SharedString>,
 1290    pub color: PlayerColor,
 1291}
 1292
 1293#[derive(Clone, Debug)]
 1294struct SelectionHistoryEntry {
 1295    selections: Arc<[Selection<Anchor>]>,
 1296    select_next_state: Option<SelectNextState>,
 1297    select_prev_state: Option<SelectNextState>,
 1298    add_selections_state: Option<AddSelectionsState>,
 1299}
 1300
 1301#[derive(Copy, Clone, Default, Debug, PartialEq, Eq)]
 1302enum SelectionHistoryMode {
 1303    #[default]
 1304    Normal,
 1305    Undoing,
 1306    Redoing,
 1307    Skipping,
 1308}
 1309
 1310#[derive(Clone, PartialEq, Eq, Hash)]
 1311struct HoveredCursor {
 1312    replica_id: ReplicaId,
 1313    selection_id: usize,
 1314}
 1315
 1316#[derive(Debug)]
 1317/// SelectionEffects controls the side-effects of updating the selection.
 1318///
 1319/// The default behaviour does "what you mostly want":
 1320/// - it pushes to the nav history if the cursor moved by >10 lines
 1321/// - it re-triggers completion requests
 1322/// - it scrolls to fit
 1323///
 1324/// You might want to modify these behaviours. For example when doing a "jump"
 1325/// like go to definition, we always want to add to nav history; but when scrolling
 1326/// in vim mode we never do.
 1327///
 1328/// Similarly, you might want to disable scrolling if you don't want the viewport to
 1329/// move.
 1330#[derive(Clone)]
 1331pub struct SelectionEffects {
 1332    nav_history: Option<bool>,
 1333    completions: bool,
 1334    scroll: Option<Autoscroll>,
 1335}
 1336
 1337impl Default for SelectionEffects {
 1338    fn default() -> Self {
 1339        Self {
 1340            nav_history: None,
 1341            completions: true,
 1342            scroll: Some(Autoscroll::fit()),
 1343        }
 1344    }
 1345}
 1346impl SelectionEffects {
 1347    pub fn scroll(scroll: Autoscroll) -> Self {
 1348        Self {
 1349            scroll: Some(scroll),
 1350            ..Default::default()
 1351        }
 1352    }
 1353
 1354    pub fn no_scroll() -> Self {
 1355        Self {
 1356            scroll: None,
 1357            ..Default::default()
 1358        }
 1359    }
 1360
 1361    pub fn completions(self, completions: bool) -> Self {
 1362        Self {
 1363            completions,
 1364            ..self
 1365        }
 1366    }
 1367
 1368    pub fn nav_history(self, nav_history: bool) -> Self {
 1369        Self {
 1370            nav_history: Some(nav_history),
 1371            ..self
 1372        }
 1373    }
 1374}
 1375
 1376struct DeferredSelectionEffectsState {
 1377    changed: bool,
 1378    effects: SelectionEffects,
 1379    old_cursor_position: Anchor,
 1380    history_entry: SelectionHistoryEntry,
 1381}
 1382
 1383#[derive(Default)]
 1384struct SelectionHistory {
 1385    #[allow(clippy::type_complexity)]
 1386    selections_by_transaction:
 1387        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1388    mode: SelectionHistoryMode,
 1389    undo_stack: VecDeque<SelectionHistoryEntry>,
 1390    redo_stack: VecDeque<SelectionHistoryEntry>,
 1391}
 1392
 1393impl SelectionHistory {
 1394    #[track_caller]
 1395    fn insert_transaction(
 1396        &mut self,
 1397        transaction_id: TransactionId,
 1398        selections: Arc<[Selection<Anchor>]>,
 1399    ) {
 1400        if selections.is_empty() {
 1401            log::error!(
 1402                "SelectionHistory::insert_transaction called with empty selections. Caller: {}",
 1403                std::panic::Location::caller()
 1404            );
 1405            return;
 1406        }
 1407        self.selections_by_transaction
 1408            .insert(transaction_id, (selections, None));
 1409    }
 1410
 1411    #[allow(clippy::type_complexity)]
 1412    fn transaction(
 1413        &self,
 1414        transaction_id: TransactionId,
 1415    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1416        self.selections_by_transaction.get(&transaction_id)
 1417    }
 1418
 1419    #[allow(clippy::type_complexity)]
 1420    fn transaction_mut(
 1421        &mut self,
 1422        transaction_id: TransactionId,
 1423    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1424        self.selections_by_transaction.get_mut(&transaction_id)
 1425    }
 1426
 1427    fn push(&mut self, entry: SelectionHistoryEntry) {
 1428        if !entry.selections.is_empty() {
 1429            match self.mode {
 1430                SelectionHistoryMode::Normal => {
 1431                    self.push_undo(entry);
 1432                    self.redo_stack.clear();
 1433                }
 1434                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1435                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1436                SelectionHistoryMode::Skipping => {}
 1437            }
 1438        }
 1439    }
 1440
 1441    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1442        if self
 1443            .undo_stack
 1444            .back()
 1445            .is_none_or(|e| e.selections != entry.selections)
 1446        {
 1447            self.undo_stack.push_back(entry);
 1448            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1449                self.undo_stack.pop_front();
 1450            }
 1451        }
 1452    }
 1453
 1454    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1455        if self
 1456            .redo_stack
 1457            .back()
 1458            .is_none_or(|e| e.selections != entry.selections)
 1459        {
 1460            self.redo_stack.push_back(entry);
 1461            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1462                self.redo_stack.pop_front();
 1463            }
 1464        }
 1465    }
 1466}
 1467
 1468#[derive(Clone, Copy)]
 1469pub struct RowHighlightOptions {
 1470    pub autoscroll: bool,
 1471    pub include_gutter: bool,
 1472}
 1473
 1474impl Default for RowHighlightOptions {
 1475    fn default() -> Self {
 1476        Self {
 1477            autoscroll: Default::default(),
 1478            include_gutter: true,
 1479        }
 1480    }
 1481}
 1482
 1483struct RowHighlight {
 1484    index: usize,
 1485    range: Range<Anchor>,
 1486    color: Hsla,
 1487    options: RowHighlightOptions,
 1488    type_id: TypeId,
 1489}
 1490
 1491#[derive(Clone, Debug)]
 1492struct AddSelectionsState {
 1493    groups: Vec<AddSelectionsGroup>,
 1494}
 1495
 1496#[derive(Clone, Debug)]
 1497struct AddSelectionsGroup {
 1498    above: bool,
 1499    stack: Vec<usize>,
 1500}
 1501
 1502#[derive(Clone)]
 1503struct SelectNextState {
 1504    query: AhoCorasick,
 1505    wordwise: bool,
 1506    done: bool,
 1507}
 1508
 1509impl std::fmt::Debug for SelectNextState {
 1510    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1511        f.debug_struct(std::any::type_name::<Self>())
 1512            .field("wordwise", &self.wordwise)
 1513            .field("done", &self.done)
 1514            .finish()
 1515    }
 1516}
 1517
 1518#[derive(Debug)]
 1519struct AutocloseRegion {
 1520    selection_id: usize,
 1521    range: Range<Anchor>,
 1522    pair: BracketPair,
 1523}
 1524
 1525#[derive(Debug)]
 1526struct SnippetState {
 1527    ranges: Vec<Vec<Range<Anchor>>>,
 1528    active_index: usize,
 1529    choices: Vec<Option<Vec<String>>>,
 1530}
 1531
 1532#[doc(hidden)]
 1533pub struct RenameState {
 1534    pub range: Range<Anchor>,
 1535    pub old_name: Arc<str>,
 1536    pub editor: Entity<Editor>,
 1537    block_id: CustomBlockId,
 1538}
 1539
 1540struct InvalidationStack<T>(Vec<T>);
 1541
 1542struct RegisteredEditPredictionProvider {
 1543    provider: Arc<dyn EditPredictionProviderHandle>,
 1544    _subscription: Subscription,
 1545}
 1546
 1547#[derive(Debug, PartialEq, Eq)]
 1548pub struct ActiveDiagnosticGroup {
 1549    pub active_range: Range<Anchor>,
 1550    pub active_message: String,
 1551    pub group_id: usize,
 1552    pub blocks: HashSet<CustomBlockId>,
 1553}
 1554
 1555#[derive(Debug, PartialEq, Eq)]
 1556
 1557pub(crate) enum ActiveDiagnostic {
 1558    None,
 1559    All,
 1560    Group(ActiveDiagnosticGroup),
 1561}
 1562
 1563#[derive(Serialize, Deserialize, Clone, Debug)]
 1564pub struct ClipboardSelection {
 1565    /// The number of bytes in this selection.
 1566    pub len: usize,
 1567    /// Whether this was a full-line selection.
 1568    pub is_entire_line: bool,
 1569    /// The indentation of the first line when this content was originally copied.
 1570    pub first_line_indent: u32,
 1571}
 1572
 1573// selections, scroll behavior, was newest selection reversed
 1574type SelectSyntaxNodeHistoryState = (
 1575    Box<[Selection<MultiBufferOffset>]>,
 1576    SelectSyntaxNodeScrollBehavior,
 1577    bool,
 1578);
 1579
 1580#[derive(Default)]
 1581struct SelectSyntaxNodeHistory {
 1582    stack: Vec<SelectSyntaxNodeHistoryState>,
 1583    // disable temporarily to allow changing selections without losing the stack
 1584    pub disable_clearing: bool,
 1585}
 1586
 1587impl SelectSyntaxNodeHistory {
 1588    pub fn try_clear(&mut self) {
 1589        if !self.disable_clearing {
 1590            self.stack.clear();
 1591        }
 1592    }
 1593
 1594    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1595        self.stack.push(selection);
 1596    }
 1597
 1598    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1599        self.stack.pop()
 1600    }
 1601}
 1602
 1603enum SelectSyntaxNodeScrollBehavior {
 1604    CursorTop,
 1605    FitSelection,
 1606    CursorBottom,
 1607}
 1608
 1609#[derive(Debug)]
 1610pub(crate) struct NavigationData {
 1611    cursor_anchor: Anchor,
 1612    cursor_position: Point,
 1613    scroll_anchor: ScrollAnchor,
 1614    scroll_top_row: u32,
 1615}
 1616
 1617#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1618pub enum GotoDefinitionKind {
 1619    Symbol,
 1620    Declaration,
 1621    Type,
 1622    Implementation,
 1623}
 1624
 1625pub enum FormatTarget {
 1626    Buffers(HashSet<Entity<Buffer>>),
 1627    Ranges(Vec<Range<MultiBufferPoint>>),
 1628}
 1629
 1630pub(crate) struct FocusedBlock {
 1631    id: BlockId,
 1632    focus_handle: WeakFocusHandle,
 1633}
 1634
 1635#[derive(Clone)]
 1636enum JumpData {
 1637    MultiBufferRow {
 1638        row: MultiBufferRow,
 1639        line_offset_from_top: u32,
 1640    },
 1641    MultiBufferPoint {
 1642        excerpt_id: ExcerptId,
 1643        position: Point,
 1644        anchor: text::Anchor,
 1645        line_offset_from_top: u32,
 1646    },
 1647}
 1648
 1649pub enum MultibufferSelectionMode {
 1650    First,
 1651    All,
 1652}
 1653
 1654#[derive(Clone, Copy, Debug, Default)]
 1655pub struct RewrapOptions {
 1656    pub override_language_settings: bool,
 1657    pub preserve_existing_whitespace: bool,
 1658}
 1659
 1660impl Editor {
 1661    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1662        let buffer = cx.new(|cx| Buffer::local("", cx));
 1663        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1664        Self::new(EditorMode::SingleLine, buffer, None, window, cx)
 1665    }
 1666
 1667    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1668        let buffer = cx.new(|cx| Buffer::local("", cx));
 1669        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1670        Self::new(EditorMode::full(), buffer, None, window, cx)
 1671    }
 1672
 1673    pub fn auto_height(
 1674        min_lines: usize,
 1675        max_lines: usize,
 1676        window: &mut Window,
 1677        cx: &mut Context<Self>,
 1678    ) -> Self {
 1679        let buffer = cx.new(|cx| Buffer::local("", cx));
 1680        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1681        Self::new(
 1682            EditorMode::AutoHeight {
 1683                min_lines,
 1684                max_lines: Some(max_lines),
 1685            },
 1686            buffer,
 1687            None,
 1688            window,
 1689            cx,
 1690        )
 1691    }
 1692
 1693    /// Creates a new auto-height editor with a minimum number of lines but no maximum.
 1694    /// The editor grows as tall as needed to fit its content.
 1695    pub fn auto_height_unbounded(
 1696        min_lines: usize,
 1697        window: &mut Window,
 1698        cx: &mut Context<Self>,
 1699    ) -> Self {
 1700        let buffer = cx.new(|cx| Buffer::local("", cx));
 1701        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1702        Self::new(
 1703            EditorMode::AutoHeight {
 1704                min_lines,
 1705                max_lines: None,
 1706            },
 1707            buffer,
 1708            None,
 1709            window,
 1710            cx,
 1711        )
 1712    }
 1713
 1714    pub fn for_buffer(
 1715        buffer: Entity<Buffer>,
 1716        project: Option<Entity<Project>>,
 1717        window: &mut Window,
 1718        cx: &mut Context<Self>,
 1719    ) -> Self {
 1720        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1721        Self::new(EditorMode::full(), buffer, project, window, cx)
 1722    }
 1723
 1724    pub fn for_multibuffer(
 1725        buffer: Entity<MultiBuffer>,
 1726        project: Option<Entity<Project>>,
 1727        window: &mut Window,
 1728        cx: &mut Context<Self>,
 1729    ) -> Self {
 1730        Self::new(EditorMode::full(), buffer, project, window, cx)
 1731    }
 1732
 1733    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1734        let mut clone = Self::new(
 1735            self.mode.clone(),
 1736            self.buffer.clone(),
 1737            self.project.clone(),
 1738            window,
 1739            cx,
 1740        );
 1741        self.display_map.update(cx, |display_map, cx| {
 1742            let snapshot = display_map.snapshot(cx);
 1743            clone.display_map.update(cx, |display_map, cx| {
 1744                display_map.set_state(&snapshot, cx);
 1745            });
 1746        });
 1747        clone.folds_did_change(cx);
 1748        clone.selections.clone_state(&self.selections);
 1749        clone.scroll_manager.clone_state(&self.scroll_manager);
 1750        clone.searchable = self.searchable;
 1751        clone.read_only = self.read_only;
 1752        clone
 1753    }
 1754
 1755    pub fn new(
 1756        mode: EditorMode,
 1757        buffer: Entity<MultiBuffer>,
 1758        project: Option<Entity<Project>>,
 1759        window: &mut Window,
 1760        cx: &mut Context<Self>,
 1761    ) -> Self {
 1762        Editor::new_internal(mode, buffer, project, None, window, cx)
 1763    }
 1764
 1765    pub fn sticky_headers(&self, cx: &App) -> Option<Vec<OutlineItem<Anchor>>> {
 1766        let multi_buffer = self.buffer().read(cx);
 1767        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 1768        let multi_buffer_visible_start = self
 1769            .scroll_manager
 1770            .anchor()
 1771            .anchor
 1772            .to_point(&multi_buffer_snapshot);
 1773        let max_row = multi_buffer_snapshot.max_point().row;
 1774
 1775        let start_row = (multi_buffer_visible_start.row).min(max_row);
 1776        let end_row = (multi_buffer_visible_start.row + 10).min(max_row);
 1777
 1778        if let Some((excerpt_id, buffer_id, buffer)) = multi_buffer.read(cx).as_singleton() {
 1779            let outline_items = buffer
 1780                .outline_items_containing(
 1781                    Point::new(start_row, 0)..Point::new(end_row, 0),
 1782                    true,
 1783                    self.style().map(|style| style.syntax.as_ref()),
 1784                )
 1785                .into_iter()
 1786                .map(|outline_item| OutlineItem {
 1787                    depth: outline_item.depth,
 1788                    range: Anchor::range_in_buffer(*excerpt_id, buffer_id, outline_item.range),
 1789                    source_range_for_text: Anchor::range_in_buffer(
 1790                        *excerpt_id,
 1791                        buffer_id,
 1792                        outline_item.source_range_for_text,
 1793                    ),
 1794                    text: outline_item.text,
 1795                    highlight_ranges: outline_item.highlight_ranges,
 1796                    name_ranges: outline_item.name_ranges,
 1797                    body_range: outline_item
 1798                        .body_range
 1799                        .map(|range| Anchor::range_in_buffer(*excerpt_id, buffer_id, range)),
 1800                    annotation_range: outline_item
 1801                        .annotation_range
 1802                        .map(|range| Anchor::range_in_buffer(*excerpt_id, buffer_id, range)),
 1803                });
 1804            return Some(outline_items.collect());
 1805        }
 1806
 1807        None
 1808    }
 1809
 1810    fn new_internal(
 1811        mode: EditorMode,
 1812        multi_buffer: Entity<MultiBuffer>,
 1813        project: Option<Entity<Project>>,
 1814        display_map: Option<Entity<DisplayMap>>,
 1815        window: &mut Window,
 1816        cx: &mut Context<Self>,
 1817    ) -> Self {
 1818        debug_assert!(
 1819            display_map.is_none() || mode.is_minimap(),
 1820            "Providing a display map for a new editor is only intended for the minimap and might have unintended side effects otherwise!"
 1821        );
 1822
 1823        let full_mode = mode.is_full();
 1824        let is_minimap = mode.is_minimap();
 1825        let diagnostics_max_severity = if full_mode {
 1826            EditorSettings::get_global(cx)
 1827                .diagnostics_max_severity
 1828                .unwrap_or(DiagnosticSeverity::Hint)
 1829        } else {
 1830            DiagnosticSeverity::Off
 1831        };
 1832        let style = window.text_style();
 1833        let font_size = style.font_size.to_pixels(window.rem_size());
 1834        let editor = cx.entity().downgrade();
 1835        let fold_placeholder = FoldPlaceholder {
 1836            constrain_width: false,
 1837            render: Arc::new(move |fold_id, fold_range, cx| {
 1838                let editor = editor.clone();
 1839                div()
 1840                    .id(fold_id)
 1841                    .bg(cx.theme().colors().ghost_element_background)
 1842                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1843                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1844                    .rounded_xs()
 1845                    .size_full()
 1846                    .cursor_pointer()
 1847                    .child("")
 1848                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1849                    .on_click(move |_, _window, cx| {
 1850                        editor
 1851                            .update(cx, |editor, cx| {
 1852                                editor.unfold_ranges(
 1853                                    &[fold_range.start..fold_range.end],
 1854                                    true,
 1855                                    false,
 1856                                    cx,
 1857                                );
 1858                                cx.stop_propagation();
 1859                            })
 1860                            .ok();
 1861                    })
 1862                    .into_any()
 1863            }),
 1864            merge_adjacent: true,
 1865            ..FoldPlaceholder::default()
 1866        };
 1867        let display_map = display_map.unwrap_or_else(|| {
 1868            cx.new(|cx| {
 1869                DisplayMap::new(
 1870                    multi_buffer.clone(),
 1871                    style.font(),
 1872                    font_size,
 1873                    None,
 1874                    FILE_HEADER_HEIGHT,
 1875                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1876                    fold_placeholder,
 1877                    diagnostics_max_severity,
 1878                    cx,
 1879                )
 1880            })
 1881        });
 1882
 1883        let selections = SelectionsCollection::new();
 1884
 1885        let blink_manager = cx.new(|cx| {
 1886            let mut blink_manager = BlinkManager::new(CURSOR_BLINK_INTERVAL, cx);
 1887            if is_minimap {
 1888                blink_manager.disable(cx);
 1889            }
 1890            blink_manager
 1891        });
 1892
 1893        let soft_wrap_mode_override =
 1894            matches!(mode, EditorMode::SingleLine).then(|| language_settings::SoftWrap::None);
 1895
 1896        let mut project_subscriptions = Vec::new();
 1897        if full_mode && let Some(project) = project.as_ref() {
 1898            project_subscriptions.push(cx.subscribe_in(
 1899                project,
 1900                window,
 1901                |editor, _, event, window, cx| match event {
 1902                    project::Event::RefreshCodeLens => {
 1903                        // we always query lens with actions, without storing them, always refreshing them
 1904                    }
 1905                    project::Event::RefreshInlayHints {
 1906                        server_id,
 1907                        request_id,
 1908                    } => {
 1909                        editor.refresh_inlay_hints(
 1910                            InlayHintRefreshReason::RefreshRequested {
 1911                                server_id: *server_id,
 1912                                request_id: *request_id,
 1913                            },
 1914                            cx,
 1915                        );
 1916                    }
 1917                    project::Event::LanguageServerRemoved(..) => {
 1918                        if editor.tasks_update_task.is_none() {
 1919                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1920                        }
 1921                        editor.registered_buffers.clear();
 1922                        editor.register_visible_buffers(cx);
 1923                    }
 1924                    project::Event::LanguageServerAdded(..) => {
 1925                        if editor.tasks_update_task.is_none() {
 1926                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1927                        }
 1928                    }
 1929                    project::Event::SnippetEdit(id, snippet_edits) => {
 1930                        // todo(lw): Non singletons
 1931                        if let Some(buffer) = editor.buffer.read(cx).as_singleton() {
 1932                            let snapshot = buffer.read(cx).snapshot();
 1933                            let focus_handle = editor.focus_handle(cx);
 1934                            if snapshot.remote_id() == *id && focus_handle.is_focused(window) {
 1935                                for (range, snippet) in snippet_edits {
 1936                                    let buffer_range =
 1937                                        language::range_from_lsp(*range).to_offset(&snapshot);
 1938                                    editor
 1939                                        .insert_snippet(
 1940                                            &[MultiBufferOffset(buffer_range.start)
 1941                                                ..MultiBufferOffset(buffer_range.end)],
 1942                                            snippet.clone(),
 1943                                            window,
 1944                                            cx,
 1945                                        )
 1946                                        .ok();
 1947                                }
 1948                            }
 1949                        }
 1950                    }
 1951                    project::Event::LanguageServerBufferRegistered { buffer_id, .. } => {
 1952                        let buffer_id = *buffer_id;
 1953                        if editor.buffer().read(cx).buffer(buffer_id).is_some() {
 1954                            editor.register_buffer(buffer_id, cx);
 1955                            editor.update_lsp_data(Some(buffer_id), window, cx);
 1956                            editor.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
 1957                            refresh_linked_ranges(editor, window, cx);
 1958                            editor.refresh_code_actions(window, cx);
 1959                            editor.refresh_document_highlights(cx);
 1960                        }
 1961                    }
 1962
 1963                    project::Event::EntryRenamed(transaction, project_path, abs_path) => {
 1964                        let Some(workspace) = editor.workspace() else {
 1965                            return;
 1966                        };
 1967                        let Some(active_editor) = workspace.read(cx).active_item_as::<Self>(cx)
 1968                        else {
 1969                            return;
 1970                        };
 1971
 1972                        if active_editor.entity_id() == cx.entity_id() {
 1973                            let entity_id = cx.entity_id();
 1974                            workspace.update(cx, |this, cx| {
 1975                                this.panes_mut()
 1976                                    .iter_mut()
 1977                                    .filter(|pane| pane.entity_id() != entity_id)
 1978                                    .for_each(|p| {
 1979                                        p.update(cx, |pane, _| {
 1980                                            pane.nav_history_mut().rename_item(
 1981                                                entity_id,
 1982                                                project_path.clone(),
 1983                                                abs_path.clone().into(),
 1984                                            );
 1985                                        })
 1986                                    });
 1987                            });
 1988                            let edited_buffers_already_open = {
 1989                                let other_editors: Vec<Entity<Editor>> = workspace
 1990                                    .read(cx)
 1991                                    .panes()
 1992                                    .iter()
 1993                                    .flat_map(|pane| pane.read(cx).items_of_type::<Editor>())
 1994                                    .filter(|editor| editor.entity_id() != cx.entity_id())
 1995                                    .collect();
 1996
 1997                                transaction.0.keys().all(|buffer| {
 1998                                    other_editors.iter().any(|editor| {
 1999                                        let multi_buffer = editor.read(cx).buffer();
 2000                                        multi_buffer.read(cx).is_singleton()
 2001                                            && multi_buffer.read(cx).as_singleton().map_or(
 2002                                                false,
 2003                                                |singleton| {
 2004                                                    singleton.entity_id() == buffer.entity_id()
 2005                                                },
 2006                                            )
 2007                                    })
 2008                                })
 2009                            };
 2010                            if !edited_buffers_already_open {
 2011                                let workspace = workspace.downgrade();
 2012                                let transaction = transaction.clone();
 2013                                cx.defer_in(window, move |_, window, cx| {
 2014                                    cx.spawn_in(window, async move |editor, cx| {
 2015                                        Self::open_project_transaction(
 2016                                            &editor,
 2017                                            workspace,
 2018                                            transaction,
 2019                                            "Rename".to_string(),
 2020                                            cx,
 2021                                        )
 2022                                        .await
 2023                                        .ok()
 2024                                    })
 2025                                    .detach();
 2026                                });
 2027                            }
 2028                        }
 2029                    }
 2030
 2031                    _ => {}
 2032                },
 2033            ));
 2034            if let Some(task_inventory) = project
 2035                .read(cx)
 2036                .task_store()
 2037                .read(cx)
 2038                .task_inventory()
 2039                .cloned()
 2040            {
 2041                project_subscriptions.push(cx.observe_in(
 2042                    &task_inventory,
 2043                    window,
 2044                    |editor, _, window, cx| {
 2045                        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2046                    },
 2047                ));
 2048            };
 2049
 2050            project_subscriptions.push(cx.subscribe_in(
 2051                &project.read(cx).breakpoint_store(),
 2052                window,
 2053                |editor, _, event, window, cx| match event {
 2054                    BreakpointStoreEvent::ClearDebugLines => {
 2055                        editor.clear_row_highlights::<ActiveDebugLine>();
 2056                        editor.refresh_inline_values(cx);
 2057                    }
 2058                    BreakpointStoreEvent::SetDebugLine => {
 2059                        if editor.go_to_active_debug_line(window, cx) {
 2060                            cx.stop_propagation();
 2061                        }
 2062
 2063                        editor.refresh_inline_values(cx);
 2064                    }
 2065                    _ => {}
 2066                },
 2067            ));
 2068            let git_store = project.read(cx).git_store().clone();
 2069            let project = project.clone();
 2070            project_subscriptions.push(cx.subscribe(&git_store, move |this, _, event, cx| {
 2071                if let GitStoreEvent::RepositoryAdded = event {
 2072                    this.load_diff_task = Some(
 2073                        update_uncommitted_diff_for_buffer(
 2074                            cx.entity(),
 2075                            &project,
 2076                            this.buffer.read(cx).all_buffers(),
 2077                            this.buffer.clone(),
 2078                            cx,
 2079                        )
 2080                        .shared(),
 2081                    );
 2082                }
 2083            }));
 2084        }
 2085
 2086        let buffer_snapshot = multi_buffer.read(cx).snapshot(cx);
 2087
 2088        let inlay_hint_settings =
 2089            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 2090        let focus_handle = cx.focus_handle();
 2091        if !is_minimap {
 2092            cx.on_focus(&focus_handle, window, Self::handle_focus)
 2093                .detach();
 2094            cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 2095                .detach();
 2096            cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 2097                .detach();
 2098            cx.on_blur(&focus_handle, window, Self::handle_blur)
 2099                .detach();
 2100            cx.observe_pending_input(window, Self::observe_pending_input)
 2101                .detach();
 2102        }
 2103
 2104        let show_indent_guides =
 2105            if matches!(mode, EditorMode::SingleLine | EditorMode::Minimap { .. }) {
 2106                Some(false)
 2107            } else {
 2108                None
 2109            };
 2110
 2111        let breakpoint_store = match (&mode, project.as_ref()) {
 2112            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 2113            _ => None,
 2114        };
 2115
 2116        let mut code_action_providers = Vec::new();
 2117        let mut load_uncommitted_diff = None;
 2118        if let Some(project) = project.clone() {
 2119            load_uncommitted_diff = Some(
 2120                update_uncommitted_diff_for_buffer(
 2121                    cx.entity(),
 2122                    &project,
 2123                    multi_buffer.read(cx).all_buffers(),
 2124                    multi_buffer.clone(),
 2125                    cx,
 2126                )
 2127                .shared(),
 2128            );
 2129            code_action_providers.push(Rc::new(project) as Rc<_>);
 2130        }
 2131
 2132        let mut editor = Self {
 2133            focus_handle,
 2134            show_cursor_when_unfocused: false,
 2135            last_focused_descendant: None,
 2136            buffer: multi_buffer.clone(),
 2137            display_map: display_map.clone(),
 2138            placeholder_display_map: None,
 2139            selections,
 2140            scroll_manager: ScrollManager::new(cx),
 2141            columnar_selection_state: None,
 2142            add_selections_state: None,
 2143            select_next_state: None,
 2144            select_prev_state: None,
 2145            selection_history: SelectionHistory::default(),
 2146            defer_selection_effects: false,
 2147            deferred_selection_effects_state: None,
 2148            autoclose_regions: Vec::new(),
 2149            snippet_stack: InvalidationStack::default(),
 2150            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 2151            ime_transaction: None,
 2152            active_diagnostics: ActiveDiagnostic::None,
 2153            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 2154            inline_diagnostics_update: Task::ready(()),
 2155            inline_diagnostics: Vec::new(),
 2156            soft_wrap_mode_override,
 2157            diagnostics_max_severity,
 2158            hard_wrap: None,
 2159            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 2160            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 2161            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 2162            project,
 2163            blink_manager: blink_manager.clone(),
 2164            show_local_selections: true,
 2165            show_scrollbars: ScrollbarAxes {
 2166                horizontal: full_mode,
 2167                vertical: full_mode,
 2168            },
 2169            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 2170            offset_content: !matches!(mode, EditorMode::SingleLine),
 2171            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 2172            show_gutter: full_mode,
 2173            show_line_numbers: (!full_mode).then_some(false),
 2174            use_relative_line_numbers: None,
 2175            disable_expand_excerpt_buttons: !full_mode,
 2176            show_git_diff_gutter: None,
 2177            show_code_actions: None,
 2178            show_runnables: None,
 2179            show_breakpoints: None,
 2180            show_wrap_guides: None,
 2181            show_indent_guides,
 2182            highlight_order: 0,
 2183            highlighted_rows: HashMap::default(),
 2184            background_highlights: HashMap::default(),
 2185            gutter_highlights: HashMap::default(),
 2186            scrollbar_marker_state: ScrollbarMarkerState::default(),
 2187            active_indent_guides_state: ActiveIndentGuidesState::default(),
 2188            nav_history: None,
 2189            context_menu: RefCell::new(None),
 2190            context_menu_options: None,
 2191            mouse_context_menu: None,
 2192            completion_tasks: Vec::new(),
 2193            inline_blame_popover: None,
 2194            inline_blame_popover_show_task: None,
 2195            signature_help_state: SignatureHelpState::default(),
 2196            auto_signature_help: None,
 2197            find_all_references_task_sources: Vec::new(),
 2198            next_completion_id: 0,
 2199            next_inlay_id: 0,
 2200            code_action_providers,
 2201            available_code_actions: None,
 2202            code_actions_task: None,
 2203            quick_selection_highlight_task: None,
 2204            debounced_selection_highlight_task: None,
 2205            document_highlights_task: None,
 2206            linked_editing_range_task: None,
 2207            pending_rename: None,
 2208            searchable: !is_minimap,
 2209            cursor_shape: EditorSettings::get_global(cx)
 2210                .cursor_shape
 2211                .unwrap_or_default(),
 2212            current_line_highlight: None,
 2213            autoindent_mode: Some(AutoindentMode::EachLine),
 2214            collapse_matches: false,
 2215            workspace: None,
 2216            input_enabled: !is_minimap,
 2217            use_modal_editing: full_mode,
 2218            read_only: is_minimap,
 2219            use_autoclose: true,
 2220            use_auto_surround: true,
 2221            auto_replace_emoji_shortcode: false,
 2222            jsx_tag_auto_close_enabled_in_any_buffer: false,
 2223            leader_id: None,
 2224            remote_id: None,
 2225            hover_state: HoverState::default(),
 2226            pending_mouse_down: None,
 2227            hovered_link_state: None,
 2228            edit_prediction_provider: None,
 2229            active_edit_prediction: None,
 2230            stale_edit_prediction_in_menu: None,
 2231            edit_prediction_preview: EditPredictionPreview::Inactive {
 2232                released_too_fast: false,
 2233            },
 2234            inline_diagnostics_enabled: full_mode,
 2235            diagnostics_enabled: full_mode,
 2236            word_completions_enabled: full_mode,
 2237            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 2238            gutter_hovered: false,
 2239            pixel_position_of_newest_cursor: None,
 2240            last_bounds: None,
 2241            last_position_map: None,
 2242            expect_bounds_change: None,
 2243            gutter_dimensions: GutterDimensions::default(),
 2244            style: None,
 2245            show_cursor_names: false,
 2246            hovered_cursors: HashMap::default(),
 2247            next_editor_action_id: EditorActionId::default(),
 2248            editor_actions: Rc::default(),
 2249            edit_predictions_hidden_for_vim_mode: false,
 2250            show_edit_predictions_override: None,
 2251            menu_edit_predictions_policy: MenuEditPredictionsPolicy::ByProvider,
 2252            edit_prediction_settings: EditPredictionSettings::Disabled,
 2253            edit_prediction_indent_conflict: false,
 2254            edit_prediction_requires_modifier_in_indent_conflict: true,
 2255            custom_context_menu: None,
 2256            show_git_blame_gutter: false,
 2257            show_git_blame_inline: false,
 2258            show_selection_menu: None,
 2259            show_git_blame_inline_delay_task: None,
 2260            git_blame_inline_enabled: full_mode
 2261                && ProjectSettings::get_global(cx).git.inline_blame.enabled,
 2262            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 2263            buffer_serialization: is_minimap.not().then(|| {
 2264                BufferSerialization::new(
 2265                    ProjectSettings::get_global(cx)
 2266                        .session
 2267                        .restore_unsaved_buffers,
 2268                )
 2269            }),
 2270            blame: None,
 2271            blame_subscription: None,
 2272            tasks: BTreeMap::default(),
 2273
 2274            breakpoint_store,
 2275            gutter_breakpoint_indicator: (None, None),
 2276            hovered_diff_hunk_row: None,
 2277            _subscriptions: (!is_minimap)
 2278                .then(|| {
 2279                    vec![
 2280                        cx.observe(&multi_buffer, Self::on_buffer_changed),
 2281                        cx.subscribe_in(&multi_buffer, window, Self::on_buffer_event),
 2282                        cx.observe_in(&display_map, window, Self::on_display_map_changed),
 2283                        cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 2284                        cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 2285                        observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 2286                        cx.observe_window_activation(window, |editor, window, cx| {
 2287                            let active = window.is_window_active();
 2288                            editor.blink_manager.update(cx, |blink_manager, cx| {
 2289                                if active {
 2290                                    blink_manager.enable(cx);
 2291                                } else {
 2292                                    blink_manager.disable(cx);
 2293                                }
 2294                            });
 2295                            if active {
 2296                                editor.show_mouse_cursor(cx);
 2297                            }
 2298                        }),
 2299                    ]
 2300                })
 2301                .unwrap_or_default(),
 2302            tasks_update_task: None,
 2303            pull_diagnostics_task: Task::ready(()),
 2304            colors: None,
 2305            refresh_colors_task: Task::ready(()),
 2306            inlay_hints: None,
 2307            next_color_inlay_id: 0,
 2308            post_scroll_update: Task::ready(()),
 2309            linked_edit_ranges: Default::default(),
 2310            in_project_search: false,
 2311            previous_search_ranges: None,
 2312            breadcrumb_header: None,
 2313            focused_block: None,
 2314            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 2315            addons: HashMap::default(),
 2316            registered_buffers: HashMap::default(),
 2317            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 2318            selection_mark_mode: false,
 2319            toggle_fold_multiple_buffers: Task::ready(()),
 2320            serialize_selections: Task::ready(()),
 2321            serialize_folds: Task::ready(()),
 2322            text_style_refinement: None,
 2323            load_diff_task: load_uncommitted_diff,
 2324            temporary_diff_override: false,
 2325            mouse_cursor_hidden: false,
 2326            minimap: None,
 2327            hide_mouse_mode: EditorSettings::get_global(cx)
 2328                .hide_mouse
 2329                .unwrap_or_default(),
 2330            change_list: ChangeList::new(),
 2331            mode,
 2332            selection_drag_state: SelectionDragState::None,
 2333            folding_newlines: Task::ready(()),
 2334            lookup_key: None,
 2335            select_next_is_case_sensitive: 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                    let vim_mode = vim_mode_setting::VimModeSetting::try_get(cx)
 2388                        .map(|vim_mode| vim_mode.0)
 2389                        .unwrap_or(false);
 2390                    if !vim_mode {
 2391                        let display_map = editor.display_snapshot(cx);
 2392                        let selections = editor.selections.all_adjusted_display(&display_map);
 2393                        let pop_state = editor
 2394                            .change_list
 2395                            .last()
 2396                            .map(|previous| {
 2397                                previous.len() == selections.len()
 2398                                    && previous.iter().enumerate().all(|(ix, p)| {
 2399                                        p.to_display_point(&display_map).row()
 2400                                            == selections[ix].head().row()
 2401                                    })
 2402                            })
 2403                            .unwrap_or(false);
 2404                        let new_positions = selections
 2405                            .into_iter()
 2406                            .map(|s| display_map.display_point_to_anchor(s.head(), Bias::Left))
 2407                            .collect();
 2408                        editor
 2409                            .change_list
 2410                            .push_to_change_list(pop_state, new_positions);
 2411                    }
 2412                }
 2413                _ => (),
 2414            },
 2415        ));
 2416
 2417        if let Some(dap_store) = editor
 2418            .project
 2419            .as_ref()
 2420            .map(|project| project.read(cx).dap_store())
 2421        {
 2422            let weak_editor = cx.weak_entity();
 2423
 2424            editor
 2425                ._subscriptions
 2426                .push(
 2427                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2428                        let session_entity = cx.entity();
 2429                        weak_editor
 2430                            .update(cx, |editor, cx| {
 2431                                editor._subscriptions.push(
 2432                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2433                                );
 2434                            })
 2435                            .ok();
 2436                    }),
 2437                );
 2438
 2439            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2440                editor
 2441                    ._subscriptions
 2442                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2443            }
 2444        }
 2445
 2446        // skip adding the initial selection to selection history
 2447        editor.selection_history.mode = SelectionHistoryMode::Skipping;
 2448        editor.end_selection(window, cx);
 2449        editor.selection_history.mode = SelectionHistoryMode::Normal;
 2450
 2451        editor.scroll_manager.show_scrollbars(window, cx);
 2452        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut editor, &multi_buffer, cx);
 2453
 2454        if full_mode {
 2455            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2456            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2457
 2458            if editor.git_blame_inline_enabled {
 2459                editor.start_git_blame_inline(false, window, cx);
 2460            }
 2461
 2462            editor.go_to_active_debug_line(window, cx);
 2463
 2464            editor.minimap =
 2465                editor.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2466            editor.colors = Some(LspColorData::new(cx));
 2467            editor.inlay_hints = Some(LspInlayHintData::new(inlay_hint_settings));
 2468
 2469            if let Some(buffer) = multi_buffer.read(cx).as_singleton() {
 2470                editor.register_buffer(buffer.read(cx).remote_id(), cx);
 2471            }
 2472            editor.update_lsp_data(None, window, cx);
 2473            editor.report_editor_event(ReportEditorEvent::EditorOpened, None, cx);
 2474        }
 2475
 2476        editor
 2477    }
 2478
 2479    pub fn display_snapshot(&self, cx: &mut App) -> DisplaySnapshot {
 2480        self.display_map.update(cx, |map, cx| map.snapshot(cx))
 2481    }
 2482
 2483    pub fn deploy_mouse_context_menu(
 2484        &mut self,
 2485        position: gpui::Point<Pixels>,
 2486        context_menu: Entity<ContextMenu>,
 2487        window: &mut Window,
 2488        cx: &mut Context<Self>,
 2489    ) {
 2490        self.mouse_context_menu = Some(MouseContextMenu::new(
 2491            self,
 2492            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2493            context_menu,
 2494            window,
 2495            cx,
 2496        ));
 2497    }
 2498
 2499    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2500        self.mouse_context_menu
 2501            .as_ref()
 2502            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2503    }
 2504
 2505    pub fn is_range_selected(&mut self, range: &Range<Anchor>, cx: &mut Context<Self>) -> bool {
 2506        if self
 2507            .selections
 2508            .pending_anchor()
 2509            .is_some_and(|pending_selection| {
 2510                let snapshot = self.buffer().read(cx).snapshot(cx);
 2511                pending_selection.range().includes(range, &snapshot)
 2512            })
 2513        {
 2514            return true;
 2515        }
 2516
 2517        self.selections
 2518            .disjoint_in_range::<MultiBufferOffset>(range.clone(), &self.display_snapshot(cx))
 2519            .into_iter()
 2520            .any(|selection| {
 2521                // This is needed to cover a corner case, if we just check for an existing
 2522                // selection in the fold range, having a cursor at the start of the fold
 2523                // marks it as selected. Non-empty selections don't cause this.
 2524                let length = selection.end - selection.start;
 2525                length > 0
 2526            })
 2527    }
 2528
 2529    pub fn key_context(&self, window: &mut Window, cx: &mut App) -> KeyContext {
 2530        self.key_context_internal(self.has_active_edit_prediction(), window, cx)
 2531    }
 2532
 2533    fn key_context_internal(
 2534        &self,
 2535        has_active_edit_prediction: bool,
 2536        window: &mut Window,
 2537        cx: &mut App,
 2538    ) -> KeyContext {
 2539        let mut key_context = KeyContext::new_with_defaults();
 2540        key_context.add("Editor");
 2541        let mode = match self.mode {
 2542            EditorMode::SingleLine => "single_line",
 2543            EditorMode::AutoHeight { .. } => "auto_height",
 2544            EditorMode::Minimap { .. } => "minimap",
 2545            EditorMode::Full { .. } => "full",
 2546        };
 2547
 2548        if EditorSettings::jupyter_enabled(cx) {
 2549            key_context.add("jupyter");
 2550        }
 2551
 2552        key_context.set("mode", mode);
 2553        if self.pending_rename.is_some() {
 2554            key_context.add("renaming");
 2555        }
 2556
 2557        if let Some(snippet_stack) = self.snippet_stack.last() {
 2558            key_context.add("in_snippet");
 2559
 2560            if snippet_stack.active_index > 0 {
 2561                key_context.add("has_previous_tabstop");
 2562            }
 2563
 2564            if snippet_stack.active_index < snippet_stack.ranges.len().saturating_sub(1) {
 2565                key_context.add("has_next_tabstop");
 2566            }
 2567        }
 2568
 2569        match self.context_menu.borrow().as_ref() {
 2570            Some(CodeContextMenu::Completions(menu)) => {
 2571                if menu.visible() {
 2572                    key_context.add("menu");
 2573                    key_context.add("showing_completions");
 2574                }
 2575            }
 2576            Some(CodeContextMenu::CodeActions(menu)) => {
 2577                if menu.visible() {
 2578                    key_context.add("menu");
 2579                    key_context.add("showing_code_actions")
 2580                }
 2581            }
 2582            None => {}
 2583        }
 2584
 2585        if self.signature_help_state.has_multiple_signatures() {
 2586            key_context.add("showing_signature_help");
 2587        }
 2588
 2589        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2590        if !self.focus_handle(cx).contains_focused(window, cx)
 2591            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2592        {
 2593            for addon in self.addons.values() {
 2594                addon.extend_key_context(&mut key_context, cx)
 2595            }
 2596        }
 2597
 2598        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2599            if let Some(extension) = singleton_buffer.read(cx).file().and_then(|file| {
 2600                Some(
 2601                    file.full_path(cx)
 2602                        .extension()?
 2603                        .to_string_lossy()
 2604                        .into_owned(),
 2605                )
 2606            }) {
 2607                key_context.set("extension", extension);
 2608            }
 2609        } else {
 2610            key_context.add("multibuffer");
 2611        }
 2612
 2613        if has_active_edit_prediction {
 2614            if self.edit_prediction_in_conflict() {
 2615                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2616            } else {
 2617                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2618                key_context.add("copilot_suggestion");
 2619            }
 2620        }
 2621
 2622        if self.selection_mark_mode {
 2623            key_context.add("selection_mode");
 2624        }
 2625
 2626        let disjoint = self.selections.disjoint_anchors();
 2627        let snapshot = self.snapshot(window, cx);
 2628        let snapshot = snapshot.buffer_snapshot();
 2629        if self.mode == EditorMode::SingleLine
 2630            && let [selection] = disjoint
 2631            && selection.start == selection.end
 2632            && selection.end.to_offset(snapshot) == snapshot.len()
 2633        {
 2634            key_context.add("end_of_input");
 2635        }
 2636
 2637        if self.has_any_expanded_diff_hunks(cx) {
 2638            key_context.add("diffs_expanded");
 2639        }
 2640
 2641        key_context
 2642    }
 2643
 2644    pub fn last_bounds(&self) -> Option<&Bounds<Pixels>> {
 2645        self.last_bounds.as_ref()
 2646    }
 2647
 2648    fn show_mouse_cursor(&mut self, cx: &mut Context<Self>) {
 2649        if self.mouse_cursor_hidden {
 2650            self.mouse_cursor_hidden = false;
 2651            cx.notify();
 2652        }
 2653    }
 2654
 2655    pub fn hide_mouse_cursor(&mut self, origin: HideMouseCursorOrigin, cx: &mut Context<Self>) {
 2656        let hide_mouse_cursor = match origin {
 2657            HideMouseCursorOrigin::TypingAction => {
 2658                matches!(
 2659                    self.hide_mouse_mode,
 2660                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2661                )
 2662            }
 2663            HideMouseCursorOrigin::MovementAction => {
 2664                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2665            }
 2666        };
 2667        if self.mouse_cursor_hidden != hide_mouse_cursor {
 2668            self.mouse_cursor_hidden = hide_mouse_cursor;
 2669            cx.notify();
 2670        }
 2671    }
 2672
 2673    pub fn edit_prediction_in_conflict(&self) -> bool {
 2674        if !self.show_edit_predictions_in_menu() {
 2675            return false;
 2676        }
 2677
 2678        let showing_completions = self
 2679            .context_menu
 2680            .borrow()
 2681            .as_ref()
 2682            .is_some_and(|context| matches!(context, CodeContextMenu::Completions(_)));
 2683
 2684        showing_completions
 2685            || self.edit_prediction_requires_modifier()
 2686            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2687            // bindings to insert tab characters.
 2688            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2689    }
 2690
 2691    pub fn accept_edit_prediction_keybind(
 2692        &self,
 2693        accept_partial: bool,
 2694        window: &mut Window,
 2695        cx: &mut App,
 2696    ) -> AcceptEditPredictionBinding {
 2697        let key_context = self.key_context_internal(true, window, cx);
 2698        let in_conflict = self.edit_prediction_in_conflict();
 2699
 2700        let bindings = if accept_partial {
 2701            window.bindings_for_action_in_context(&AcceptPartialEditPrediction, key_context)
 2702        } else {
 2703            window.bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2704        };
 2705
 2706        // TODO: if the binding contains multiple keystrokes, display all of them, not
 2707        // just the first one.
 2708        AcceptEditPredictionBinding(bindings.into_iter().rev().find(|binding| {
 2709            !in_conflict
 2710                || binding
 2711                    .keystrokes()
 2712                    .first()
 2713                    .is_some_and(|keystroke| keystroke.modifiers().modified())
 2714        }))
 2715    }
 2716
 2717    pub fn new_file(
 2718        workspace: &mut Workspace,
 2719        _: &workspace::NewFile,
 2720        window: &mut Window,
 2721        cx: &mut Context<Workspace>,
 2722    ) {
 2723        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2724            "Failed to create buffer",
 2725            window,
 2726            cx,
 2727            |e, _, _| match e.error_code() {
 2728                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2729                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2730                e.error_tag("required").unwrap_or("the latest version")
 2731            )),
 2732                _ => None,
 2733            },
 2734        );
 2735    }
 2736
 2737    pub fn new_in_workspace(
 2738        workspace: &mut Workspace,
 2739        window: &mut Window,
 2740        cx: &mut Context<Workspace>,
 2741    ) -> Task<Result<Entity<Editor>>> {
 2742        let project = workspace.project().clone();
 2743        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2744
 2745        cx.spawn_in(window, async move |workspace, cx| {
 2746            let buffer = create.await?;
 2747            workspace.update_in(cx, |workspace, window, cx| {
 2748                let editor =
 2749                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2750                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2751                editor
 2752            })
 2753        })
 2754    }
 2755
 2756    fn new_file_vertical(
 2757        workspace: &mut Workspace,
 2758        _: &workspace::NewFileSplitVertical,
 2759        window: &mut Window,
 2760        cx: &mut Context<Workspace>,
 2761    ) {
 2762        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2763    }
 2764
 2765    fn new_file_horizontal(
 2766        workspace: &mut Workspace,
 2767        _: &workspace::NewFileSplitHorizontal,
 2768        window: &mut Window,
 2769        cx: &mut Context<Workspace>,
 2770    ) {
 2771        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2772    }
 2773
 2774    fn new_file_split(
 2775        workspace: &mut Workspace,
 2776        action: &workspace::NewFileSplit,
 2777        window: &mut Window,
 2778        cx: &mut Context<Workspace>,
 2779    ) {
 2780        Self::new_file_in_direction(workspace, action.0, window, cx)
 2781    }
 2782
 2783    fn new_file_in_direction(
 2784        workspace: &mut Workspace,
 2785        direction: SplitDirection,
 2786        window: &mut Window,
 2787        cx: &mut Context<Workspace>,
 2788    ) {
 2789        let project = workspace.project().clone();
 2790        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2791
 2792        cx.spawn_in(window, async move |workspace, cx| {
 2793            let buffer = create.await?;
 2794            workspace.update_in(cx, move |workspace, window, cx| {
 2795                workspace.split_item(
 2796                    direction,
 2797                    Box::new(
 2798                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2799                    ),
 2800                    window,
 2801                    cx,
 2802                )
 2803            })?;
 2804            anyhow::Ok(())
 2805        })
 2806        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2807            match e.error_code() {
 2808                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2809                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2810                e.error_tag("required").unwrap_or("the latest version")
 2811            )),
 2812                _ => None,
 2813            }
 2814        });
 2815    }
 2816
 2817    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2818        self.leader_id
 2819    }
 2820
 2821    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2822        &self.buffer
 2823    }
 2824
 2825    pub fn project(&self) -> Option<&Entity<Project>> {
 2826        self.project.as_ref()
 2827    }
 2828
 2829    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2830        self.workspace.as_ref()?.0.upgrade()
 2831    }
 2832
 2833    /// Returns the workspace serialization ID if this editor should be serialized.
 2834    fn workspace_serialization_id(&self, _cx: &App) -> Option<WorkspaceId> {
 2835        self.workspace
 2836            .as_ref()
 2837            .filter(|_| self.should_serialize_buffer())
 2838            .and_then(|workspace| workspace.1)
 2839    }
 2840
 2841    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2842        self.buffer().read(cx).title(cx)
 2843    }
 2844
 2845    pub fn snapshot(&self, window: &Window, cx: &mut App) -> EditorSnapshot {
 2846        let git_blame_gutter_max_author_length = self
 2847            .render_git_blame_gutter(cx)
 2848            .then(|| {
 2849                if let Some(blame) = self.blame.as_ref() {
 2850                    let max_author_length =
 2851                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2852                    Some(max_author_length)
 2853                } else {
 2854                    None
 2855                }
 2856            })
 2857            .flatten();
 2858
 2859        EditorSnapshot {
 2860            mode: self.mode.clone(),
 2861            show_gutter: self.show_gutter,
 2862            show_line_numbers: self.show_line_numbers,
 2863            show_git_diff_gutter: self.show_git_diff_gutter,
 2864            show_code_actions: self.show_code_actions,
 2865            show_runnables: self.show_runnables,
 2866            show_breakpoints: self.show_breakpoints,
 2867            git_blame_gutter_max_author_length,
 2868            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2869            placeholder_display_snapshot: self
 2870                .placeholder_display_map
 2871                .as_ref()
 2872                .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx))),
 2873            scroll_anchor: self.scroll_manager.anchor(),
 2874            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2875            is_focused: self.focus_handle.is_focused(window),
 2876            current_line_highlight: self
 2877                .current_line_highlight
 2878                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2879            gutter_hovered: self.gutter_hovered,
 2880        }
 2881    }
 2882
 2883    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2884        self.buffer.read(cx).language_at(point, cx)
 2885    }
 2886
 2887    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2888        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2889    }
 2890
 2891    pub fn active_excerpt(
 2892        &self,
 2893        cx: &App,
 2894    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2895        self.buffer
 2896            .read(cx)
 2897            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2898    }
 2899
 2900    pub fn mode(&self) -> &EditorMode {
 2901        &self.mode
 2902    }
 2903
 2904    pub fn set_mode(&mut self, mode: EditorMode) {
 2905        self.mode = mode;
 2906    }
 2907
 2908    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2909        self.collaboration_hub.as_deref()
 2910    }
 2911
 2912    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2913        self.collaboration_hub = Some(hub);
 2914    }
 2915
 2916    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2917        self.in_project_search = in_project_search;
 2918    }
 2919
 2920    pub fn set_custom_context_menu(
 2921        &mut self,
 2922        f: impl 'static
 2923        + Fn(
 2924            &mut Self,
 2925            DisplayPoint,
 2926            &mut Window,
 2927            &mut Context<Self>,
 2928        ) -> Option<Entity<ui::ContextMenu>>,
 2929    ) {
 2930        self.custom_context_menu = Some(Box::new(f))
 2931    }
 2932
 2933    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 2934        self.completion_provider = provider;
 2935    }
 2936
 2937    #[cfg(any(test, feature = "test-support"))]
 2938    pub fn completion_provider(&self) -> Option<Rc<dyn CompletionProvider>> {
 2939        self.completion_provider.clone()
 2940    }
 2941
 2942    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 2943        self.semantics_provider.clone()
 2944    }
 2945
 2946    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 2947        self.semantics_provider = provider;
 2948    }
 2949
 2950    pub fn set_edit_prediction_provider<T>(
 2951        &mut self,
 2952        provider: Option<Entity<T>>,
 2953        window: &mut Window,
 2954        cx: &mut Context<Self>,
 2955    ) where
 2956        T: EditPredictionProvider,
 2957    {
 2958        self.edit_prediction_provider = provider.map(|provider| RegisteredEditPredictionProvider {
 2959            _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 2960                if this.focus_handle.is_focused(window) {
 2961                    this.update_visible_edit_prediction(window, cx);
 2962                }
 2963            }),
 2964            provider: Arc::new(provider),
 2965        });
 2966        self.update_edit_prediction_settings(cx);
 2967        self.refresh_edit_prediction(false, false, window, cx);
 2968    }
 2969
 2970    pub fn placeholder_text(&self, cx: &mut App) -> Option<String> {
 2971        self.placeholder_display_map
 2972            .as_ref()
 2973            .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx)).text())
 2974    }
 2975
 2976    pub fn set_placeholder_text(
 2977        &mut self,
 2978        placeholder_text: &str,
 2979        window: &mut Window,
 2980        cx: &mut Context<Self>,
 2981    ) {
 2982        let multibuffer = cx
 2983            .new(|cx| MultiBuffer::singleton(cx.new(|cx| Buffer::local(placeholder_text, cx)), cx));
 2984
 2985        let style = window.text_style();
 2986
 2987        self.placeholder_display_map = Some(cx.new(|cx| {
 2988            DisplayMap::new(
 2989                multibuffer,
 2990                style.font(),
 2991                style.font_size.to_pixels(window.rem_size()),
 2992                None,
 2993                FILE_HEADER_HEIGHT,
 2994                MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 2995                Default::default(),
 2996                DiagnosticSeverity::Off,
 2997                cx,
 2998            )
 2999        }));
 3000        cx.notify();
 3001    }
 3002
 3003    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 3004        self.cursor_shape = cursor_shape;
 3005
 3006        // Disrupt blink for immediate user feedback that the cursor shape has changed
 3007        self.blink_manager.update(cx, BlinkManager::show_cursor);
 3008
 3009        cx.notify();
 3010    }
 3011
 3012    pub fn set_current_line_highlight(
 3013        &mut self,
 3014        current_line_highlight: Option<CurrentLineHighlight>,
 3015    ) {
 3016        self.current_line_highlight = current_line_highlight;
 3017    }
 3018
 3019    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 3020        self.collapse_matches = collapse_matches;
 3021    }
 3022
 3023    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 3024        if self.collapse_matches {
 3025            return range.start..range.start;
 3026        }
 3027        range.clone()
 3028    }
 3029
 3030    pub fn clip_at_line_ends(&mut self, cx: &mut Context<Self>) -> bool {
 3031        self.display_map.read(cx).clip_at_line_ends
 3032    }
 3033
 3034    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 3035        if self.display_map.read(cx).clip_at_line_ends != clip {
 3036            self.display_map
 3037                .update(cx, |map, _| map.clip_at_line_ends = clip);
 3038        }
 3039    }
 3040
 3041    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 3042        self.input_enabled = input_enabled;
 3043    }
 3044
 3045    pub fn set_edit_predictions_hidden_for_vim_mode(
 3046        &mut self,
 3047        hidden: bool,
 3048        window: &mut Window,
 3049        cx: &mut Context<Self>,
 3050    ) {
 3051        if hidden != self.edit_predictions_hidden_for_vim_mode {
 3052            self.edit_predictions_hidden_for_vim_mode = hidden;
 3053            if hidden {
 3054                self.update_visible_edit_prediction(window, cx);
 3055            } else {
 3056                self.refresh_edit_prediction(true, false, window, cx);
 3057            }
 3058        }
 3059    }
 3060
 3061    pub fn set_menu_edit_predictions_policy(&mut self, value: MenuEditPredictionsPolicy) {
 3062        self.menu_edit_predictions_policy = value;
 3063    }
 3064
 3065    pub fn set_autoindent(&mut self, autoindent: bool) {
 3066        if autoindent {
 3067            self.autoindent_mode = Some(AutoindentMode::EachLine);
 3068        } else {
 3069            self.autoindent_mode = None;
 3070        }
 3071    }
 3072
 3073    pub fn read_only(&self, cx: &App) -> bool {
 3074        self.read_only || self.buffer.read(cx).read_only()
 3075    }
 3076
 3077    pub fn set_read_only(&mut self, read_only: bool) {
 3078        self.read_only = read_only;
 3079    }
 3080
 3081    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 3082        self.use_autoclose = autoclose;
 3083    }
 3084
 3085    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 3086        self.use_auto_surround = auto_surround;
 3087    }
 3088
 3089    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 3090        self.auto_replace_emoji_shortcode = auto_replace;
 3091    }
 3092
 3093    pub fn set_should_serialize(&mut self, should_serialize: bool, cx: &App) {
 3094        self.buffer_serialization = should_serialize.then(|| {
 3095            BufferSerialization::new(
 3096                ProjectSettings::get_global(cx)
 3097                    .session
 3098                    .restore_unsaved_buffers,
 3099            )
 3100        })
 3101    }
 3102
 3103    fn should_serialize_buffer(&self) -> bool {
 3104        self.buffer_serialization.is_some()
 3105    }
 3106
 3107    pub fn toggle_edit_predictions(
 3108        &mut self,
 3109        _: &ToggleEditPrediction,
 3110        window: &mut Window,
 3111        cx: &mut Context<Self>,
 3112    ) {
 3113        if self.show_edit_predictions_override.is_some() {
 3114            self.set_show_edit_predictions(None, window, cx);
 3115        } else {
 3116            let show_edit_predictions = !self.edit_predictions_enabled();
 3117            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 3118        }
 3119    }
 3120
 3121    pub fn set_show_edit_predictions(
 3122        &mut self,
 3123        show_edit_predictions: Option<bool>,
 3124        window: &mut Window,
 3125        cx: &mut Context<Self>,
 3126    ) {
 3127        self.show_edit_predictions_override = show_edit_predictions;
 3128        self.update_edit_prediction_settings(cx);
 3129
 3130        if let Some(false) = show_edit_predictions {
 3131            self.discard_edit_prediction(false, cx);
 3132        } else {
 3133            self.refresh_edit_prediction(false, true, window, cx);
 3134        }
 3135    }
 3136
 3137    fn edit_predictions_disabled_in_scope(
 3138        &self,
 3139        buffer: &Entity<Buffer>,
 3140        buffer_position: language::Anchor,
 3141        cx: &App,
 3142    ) -> bool {
 3143        let snapshot = buffer.read(cx).snapshot();
 3144        let settings = snapshot.settings_at(buffer_position, cx);
 3145
 3146        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 3147            return false;
 3148        };
 3149
 3150        scope.override_name().is_some_and(|scope_name| {
 3151            settings
 3152                .edit_predictions_disabled_in
 3153                .iter()
 3154                .any(|s| s == scope_name)
 3155        })
 3156    }
 3157
 3158    pub fn set_use_modal_editing(&mut self, to: bool) {
 3159        self.use_modal_editing = to;
 3160    }
 3161
 3162    pub fn use_modal_editing(&self) -> bool {
 3163        self.use_modal_editing
 3164    }
 3165
 3166    fn selections_did_change(
 3167        &mut self,
 3168        local: bool,
 3169        old_cursor_position: &Anchor,
 3170        effects: SelectionEffects,
 3171        window: &mut Window,
 3172        cx: &mut Context<Self>,
 3173    ) {
 3174        window.invalidate_character_coordinates();
 3175
 3176        // Copy selections to primary selection buffer
 3177        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 3178        if local {
 3179            let selections = self
 3180                .selections
 3181                .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 3182            let buffer_handle = self.buffer.read(cx).read(cx);
 3183
 3184            let mut text = String::new();
 3185            for (index, selection) in selections.iter().enumerate() {
 3186                let text_for_selection = buffer_handle
 3187                    .text_for_range(selection.start..selection.end)
 3188                    .collect::<String>();
 3189
 3190                text.push_str(&text_for_selection);
 3191                if index != selections.len() - 1 {
 3192                    text.push('\n');
 3193                }
 3194            }
 3195
 3196            if !text.is_empty() {
 3197                cx.write_to_primary(ClipboardItem::new_string(text));
 3198            }
 3199        }
 3200
 3201        let selection_anchors = self.selections.disjoint_anchors_arc();
 3202
 3203        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 3204            self.buffer.update(cx, |buffer, cx| {
 3205                buffer.set_active_selections(
 3206                    &selection_anchors,
 3207                    self.selections.line_mode(),
 3208                    self.cursor_shape,
 3209                    cx,
 3210                )
 3211            });
 3212        }
 3213        let display_map = self
 3214            .display_map
 3215            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3216        let buffer = display_map.buffer_snapshot();
 3217        if self.selections.count() == 1 {
 3218            self.add_selections_state = None;
 3219        }
 3220        self.select_next_state = None;
 3221        self.select_prev_state = None;
 3222        self.select_syntax_node_history.try_clear();
 3223        self.invalidate_autoclose_regions(&selection_anchors, buffer);
 3224        self.snippet_stack.invalidate(&selection_anchors, buffer);
 3225        self.take_rename(false, window, cx);
 3226
 3227        let newest_selection = self.selections.newest_anchor();
 3228        let new_cursor_position = newest_selection.head();
 3229        let selection_start = newest_selection.start;
 3230
 3231        if effects.nav_history.is_none() || effects.nav_history == Some(true) {
 3232            self.push_to_nav_history(
 3233                *old_cursor_position,
 3234                Some(new_cursor_position.to_point(buffer)),
 3235                false,
 3236                effects.nav_history == Some(true),
 3237                cx,
 3238            );
 3239        }
 3240
 3241        if local {
 3242            if let Some(buffer_id) = new_cursor_position.buffer_id {
 3243                self.register_buffer(buffer_id, cx);
 3244            }
 3245
 3246            let mut context_menu = self.context_menu.borrow_mut();
 3247            let completion_menu = match context_menu.as_ref() {
 3248                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 3249                Some(CodeContextMenu::CodeActions(_)) => {
 3250                    *context_menu = None;
 3251                    None
 3252                }
 3253                None => None,
 3254            };
 3255            let completion_position = completion_menu.map(|menu| menu.initial_position);
 3256            drop(context_menu);
 3257
 3258            if effects.completions
 3259                && let Some(completion_position) = completion_position
 3260            {
 3261                let start_offset = selection_start.to_offset(buffer);
 3262                let position_matches = start_offset == completion_position.to_offset(buffer);
 3263                let continue_showing = if position_matches {
 3264                    if self.snippet_stack.is_empty() {
 3265                        buffer.char_kind_before(start_offset, Some(CharScopeContext::Completion))
 3266                            == Some(CharKind::Word)
 3267                    } else {
 3268                        // Snippet choices can be shown even when the cursor is in whitespace.
 3269                        // Dismissing the menu with actions like backspace is handled by
 3270                        // invalidation regions.
 3271                        true
 3272                    }
 3273                } else {
 3274                    false
 3275                };
 3276
 3277                if continue_showing {
 3278                    self.open_or_update_completions_menu(None, None, false, window, cx);
 3279                } else {
 3280                    self.hide_context_menu(window, cx);
 3281                }
 3282            }
 3283
 3284            hide_hover(self, cx);
 3285
 3286            if old_cursor_position.to_display_point(&display_map).row()
 3287                != new_cursor_position.to_display_point(&display_map).row()
 3288            {
 3289                self.available_code_actions.take();
 3290            }
 3291            self.refresh_code_actions(window, cx);
 3292            self.refresh_document_highlights(cx);
 3293            refresh_linked_ranges(self, window, cx);
 3294
 3295            self.refresh_selected_text_highlights(false, window, cx);
 3296            self.refresh_matching_bracket_highlights(window, cx);
 3297            self.update_visible_edit_prediction(window, cx);
 3298            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 3299            self.inline_blame_popover.take();
 3300            if self.git_blame_inline_enabled {
 3301                self.start_inline_blame_timer(window, cx);
 3302            }
 3303        }
 3304
 3305        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 3306        cx.emit(EditorEvent::SelectionsChanged { local });
 3307
 3308        let selections = &self.selections.disjoint_anchors_arc();
 3309        if selections.len() == 1 {
 3310            cx.emit(SearchEvent::ActiveMatchChanged)
 3311        }
 3312        if local && let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 3313            let inmemory_selections = selections
 3314                .iter()
 3315                .map(|s| {
 3316                    text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 3317                        ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 3318                })
 3319                .collect();
 3320            self.update_restoration_data(cx, |data| {
 3321                data.selections = inmemory_selections;
 3322            });
 3323
 3324            if WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
 3325                && let Some(workspace_id) = self.workspace_serialization_id(cx)
 3326            {
 3327                let snapshot = self.buffer().read(cx).snapshot(cx);
 3328                let selections = selections.clone();
 3329                let background_executor = cx.background_executor().clone();
 3330                let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3331                self.serialize_selections = cx.background_spawn(async move {
 3332                    background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3333                    let db_selections = selections
 3334                        .iter()
 3335                        .map(|selection| {
 3336                            (
 3337                                selection.start.to_offset(&snapshot).0,
 3338                                selection.end.to_offset(&snapshot).0,
 3339                            )
 3340                        })
 3341                        .collect();
 3342
 3343                    DB.save_editor_selections(editor_id, workspace_id, db_selections)
 3344                        .await
 3345                        .with_context(|| {
 3346                            format!(
 3347                                "persisting editor selections for editor {editor_id}, \
 3348                                workspace {workspace_id:?}"
 3349                            )
 3350                        })
 3351                        .log_err();
 3352                });
 3353            }
 3354        }
 3355
 3356        cx.notify();
 3357    }
 3358
 3359    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 3360        use text::ToOffset as _;
 3361        use text::ToPoint as _;
 3362
 3363        if self.mode.is_minimap()
 3364            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 3365        {
 3366            return;
 3367        }
 3368
 3369        if !self.buffer().read(cx).is_singleton() {
 3370            return;
 3371        }
 3372
 3373        let display_snapshot = self
 3374            .display_map
 3375            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3376        let Some((.., snapshot)) = display_snapshot.buffer_snapshot().as_singleton() else {
 3377            return;
 3378        };
 3379        let inmemory_folds = display_snapshot
 3380            .folds_in_range(MultiBufferOffset(0)..display_snapshot.buffer_snapshot().len())
 3381            .map(|fold| {
 3382                fold.range.start.text_anchor.to_point(&snapshot)
 3383                    ..fold.range.end.text_anchor.to_point(&snapshot)
 3384            })
 3385            .collect();
 3386        self.update_restoration_data(cx, |data| {
 3387            data.folds = inmemory_folds;
 3388        });
 3389
 3390        let Some(workspace_id) = self.workspace_serialization_id(cx) else {
 3391            return;
 3392        };
 3393        let background_executor = cx.background_executor().clone();
 3394        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3395        let db_folds = display_snapshot
 3396            .folds_in_range(MultiBufferOffset(0)..display_snapshot.buffer_snapshot().len())
 3397            .map(|fold| {
 3398                (
 3399                    fold.range.start.text_anchor.to_offset(&snapshot),
 3400                    fold.range.end.text_anchor.to_offset(&snapshot),
 3401                )
 3402            })
 3403            .collect();
 3404        self.serialize_folds = cx.background_spawn(async move {
 3405            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3406            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 3407                .await
 3408                .with_context(|| {
 3409                    format!(
 3410                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 3411                    )
 3412                })
 3413                .log_err();
 3414        });
 3415    }
 3416
 3417    pub fn sync_selections(
 3418        &mut self,
 3419        other: Entity<Editor>,
 3420        cx: &mut Context<Self>,
 3421    ) -> gpui::Subscription {
 3422        let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3423        if !other_selections.is_empty() {
 3424            self.selections
 3425                .change_with(&self.display_snapshot(cx), |selections| {
 3426                    selections.select_anchors(other_selections);
 3427                });
 3428        }
 3429
 3430        let other_subscription = cx.subscribe(&other, |this, other, other_evt, cx| {
 3431            if let EditorEvent::SelectionsChanged { local: true } = other_evt {
 3432                let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3433                if other_selections.is_empty() {
 3434                    return;
 3435                }
 3436                let snapshot = this.display_snapshot(cx);
 3437                this.selections.change_with(&snapshot, |selections| {
 3438                    selections.select_anchors(other_selections);
 3439                });
 3440            }
 3441        });
 3442
 3443        let this_subscription = cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| {
 3444            if let EditorEvent::SelectionsChanged { local: true } = this_evt {
 3445                let these_selections = this.selections.disjoint_anchors().to_vec();
 3446                if these_selections.is_empty() {
 3447                    return;
 3448                }
 3449                other.update(cx, |other_editor, cx| {
 3450                    let snapshot = other_editor.display_snapshot(cx);
 3451                    other_editor
 3452                        .selections
 3453                        .change_with(&snapshot, |selections| {
 3454                            selections.select_anchors(these_selections);
 3455                        })
 3456                });
 3457            }
 3458        });
 3459
 3460        Subscription::join(other_subscription, this_subscription)
 3461    }
 3462
 3463    fn unfold_buffers_with_selections(&mut self, cx: &mut Context<Self>) {
 3464        if self.buffer().read(cx).is_singleton() {
 3465            return;
 3466        }
 3467        let snapshot = self.buffer.read(cx).snapshot(cx);
 3468        let buffer_ids: HashSet<BufferId> = self
 3469            .selections
 3470            .disjoint_anchor_ranges()
 3471            .flat_map(|range| snapshot.buffer_ids_for_range(range))
 3472            .collect();
 3473        for buffer_id in buffer_ids {
 3474            self.unfold_buffer(buffer_id, cx);
 3475        }
 3476    }
 3477
 3478    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 3479    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 3480    /// effects of selection change occur at the end of the transaction.
 3481    pub fn change_selections<R>(
 3482        &mut self,
 3483        effects: SelectionEffects,
 3484        window: &mut Window,
 3485        cx: &mut Context<Self>,
 3486        change: impl FnOnce(&mut MutableSelectionsCollection<'_, '_>) -> R,
 3487    ) -> R {
 3488        let snapshot = self.display_snapshot(cx);
 3489        if let Some(state) = &mut self.deferred_selection_effects_state {
 3490            state.effects.scroll = effects.scroll.or(state.effects.scroll);
 3491            state.effects.completions = effects.completions;
 3492            state.effects.nav_history = effects.nav_history.or(state.effects.nav_history);
 3493            let (changed, result) = self.selections.change_with(&snapshot, change);
 3494            state.changed |= changed;
 3495            return result;
 3496        }
 3497        let mut state = DeferredSelectionEffectsState {
 3498            changed: false,
 3499            effects,
 3500            old_cursor_position: self.selections.newest_anchor().head(),
 3501            history_entry: SelectionHistoryEntry {
 3502                selections: self.selections.disjoint_anchors_arc(),
 3503                select_next_state: self.select_next_state.clone(),
 3504                select_prev_state: self.select_prev_state.clone(),
 3505                add_selections_state: self.add_selections_state.clone(),
 3506            },
 3507        };
 3508        let (changed, result) = self.selections.change_with(&snapshot, change);
 3509        state.changed = state.changed || changed;
 3510        if self.defer_selection_effects {
 3511            self.deferred_selection_effects_state = Some(state);
 3512        } else {
 3513            self.apply_selection_effects(state, window, cx);
 3514        }
 3515        result
 3516    }
 3517
 3518    /// Defers the effects of selection change, so that the effects of multiple calls to
 3519    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3520    /// to selection history and the state of popovers based on selection position aren't
 3521    /// erroneously updated.
 3522    pub fn with_selection_effects_deferred<R>(
 3523        &mut self,
 3524        window: &mut Window,
 3525        cx: &mut Context<Self>,
 3526        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3527    ) -> R {
 3528        let already_deferred = self.defer_selection_effects;
 3529        self.defer_selection_effects = true;
 3530        let result = update(self, window, cx);
 3531        if !already_deferred {
 3532            self.defer_selection_effects = false;
 3533            if let Some(state) = self.deferred_selection_effects_state.take() {
 3534                self.apply_selection_effects(state, window, cx);
 3535            }
 3536        }
 3537        result
 3538    }
 3539
 3540    fn apply_selection_effects(
 3541        &mut self,
 3542        state: DeferredSelectionEffectsState,
 3543        window: &mut Window,
 3544        cx: &mut Context<Self>,
 3545    ) {
 3546        if state.changed {
 3547            self.selection_history.push(state.history_entry);
 3548
 3549            if let Some(autoscroll) = state.effects.scroll {
 3550                self.request_autoscroll(autoscroll, cx);
 3551            }
 3552
 3553            let old_cursor_position = &state.old_cursor_position;
 3554
 3555            self.selections_did_change(true, old_cursor_position, state.effects, window, cx);
 3556
 3557            if self.should_open_signature_help_automatically(old_cursor_position, cx) {
 3558                self.show_signature_help(&ShowSignatureHelp, window, cx);
 3559            }
 3560        }
 3561    }
 3562
 3563    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3564    where
 3565        I: IntoIterator<Item = (Range<S>, T)>,
 3566        S: ToOffset,
 3567        T: Into<Arc<str>>,
 3568    {
 3569        if self.read_only(cx) {
 3570            return;
 3571        }
 3572
 3573        self.buffer
 3574            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3575    }
 3576
 3577    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3578    where
 3579        I: IntoIterator<Item = (Range<S>, T)>,
 3580        S: ToOffset,
 3581        T: Into<Arc<str>>,
 3582    {
 3583        if self.read_only(cx) {
 3584            return;
 3585        }
 3586
 3587        self.buffer.update(cx, |buffer, cx| {
 3588            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3589        });
 3590    }
 3591
 3592    pub fn edit_with_block_indent<I, S, T>(
 3593        &mut self,
 3594        edits: I,
 3595        original_indent_columns: Vec<Option<u32>>,
 3596        cx: &mut Context<Self>,
 3597    ) where
 3598        I: IntoIterator<Item = (Range<S>, T)>,
 3599        S: ToOffset,
 3600        T: Into<Arc<str>>,
 3601    {
 3602        if self.read_only(cx) {
 3603            return;
 3604        }
 3605
 3606        self.buffer.update(cx, |buffer, cx| {
 3607            buffer.edit(
 3608                edits,
 3609                Some(AutoindentMode::Block {
 3610                    original_indent_columns,
 3611                }),
 3612                cx,
 3613            )
 3614        });
 3615    }
 3616
 3617    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3618        self.hide_context_menu(window, cx);
 3619
 3620        match phase {
 3621            SelectPhase::Begin {
 3622                position,
 3623                add,
 3624                click_count,
 3625            } => self.begin_selection(position, add, click_count, window, cx),
 3626            SelectPhase::BeginColumnar {
 3627                position,
 3628                goal_column,
 3629                reset,
 3630                mode,
 3631            } => self.begin_columnar_selection(position, goal_column, reset, mode, window, cx),
 3632            SelectPhase::Extend {
 3633                position,
 3634                click_count,
 3635            } => self.extend_selection(position, click_count, window, cx),
 3636            SelectPhase::Update {
 3637                position,
 3638                goal_column,
 3639                scroll_delta,
 3640            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3641            SelectPhase::End => self.end_selection(window, cx),
 3642        }
 3643    }
 3644
 3645    fn extend_selection(
 3646        &mut self,
 3647        position: DisplayPoint,
 3648        click_count: usize,
 3649        window: &mut Window,
 3650        cx: &mut Context<Self>,
 3651    ) {
 3652        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3653        let tail = self
 3654            .selections
 3655            .newest::<MultiBufferOffset>(&display_map)
 3656            .tail();
 3657        let click_count = click_count.max(match self.selections.select_mode() {
 3658            SelectMode::Character => 1,
 3659            SelectMode::Word(_) => 2,
 3660            SelectMode::Line(_) => 3,
 3661            SelectMode::All => 4,
 3662        });
 3663        self.begin_selection(position, false, click_count, window, cx);
 3664
 3665        let tail_anchor = display_map.buffer_snapshot().anchor_before(tail);
 3666
 3667        let current_selection = match self.selections.select_mode() {
 3668            SelectMode::Character | SelectMode::All => tail_anchor..tail_anchor,
 3669            SelectMode::Word(range) | SelectMode::Line(range) => range.clone(),
 3670        };
 3671
 3672        let mut pending_selection = self
 3673            .selections
 3674            .pending_anchor()
 3675            .cloned()
 3676            .expect("extend_selection not called with pending selection");
 3677
 3678        if pending_selection
 3679            .start
 3680            .cmp(&current_selection.start, display_map.buffer_snapshot())
 3681            == Ordering::Greater
 3682        {
 3683            pending_selection.start = current_selection.start;
 3684        }
 3685        if pending_selection
 3686            .end
 3687            .cmp(&current_selection.end, display_map.buffer_snapshot())
 3688            == Ordering::Less
 3689        {
 3690            pending_selection.end = current_selection.end;
 3691            pending_selection.reversed = true;
 3692        }
 3693
 3694        let mut pending_mode = self.selections.pending_mode().unwrap();
 3695        match &mut pending_mode {
 3696            SelectMode::Word(range) | SelectMode::Line(range) => *range = current_selection,
 3697            _ => {}
 3698        }
 3699
 3700        let effects = if EditorSettings::get_global(cx).autoscroll_on_clicks {
 3701            SelectionEffects::scroll(Autoscroll::fit())
 3702        } else {
 3703            SelectionEffects::no_scroll()
 3704        };
 3705
 3706        self.change_selections(effects, window, cx, |s| {
 3707            s.set_pending(pending_selection.clone(), pending_mode);
 3708            s.set_is_extending(true);
 3709        });
 3710    }
 3711
 3712    fn begin_selection(
 3713        &mut self,
 3714        position: DisplayPoint,
 3715        add: bool,
 3716        click_count: usize,
 3717        window: &mut Window,
 3718        cx: &mut Context<Self>,
 3719    ) {
 3720        if !self.focus_handle.is_focused(window) {
 3721            self.last_focused_descendant = None;
 3722            window.focus(&self.focus_handle);
 3723        }
 3724
 3725        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3726        let buffer = display_map.buffer_snapshot();
 3727        let position = display_map.clip_point(position, Bias::Left);
 3728
 3729        let start;
 3730        let end;
 3731        let mode;
 3732        let mut auto_scroll;
 3733        match click_count {
 3734            1 => {
 3735                start = buffer.anchor_before(position.to_point(&display_map));
 3736                end = start;
 3737                mode = SelectMode::Character;
 3738                auto_scroll = true;
 3739            }
 3740            2 => {
 3741                let position = display_map
 3742                    .clip_point(position, Bias::Left)
 3743                    .to_offset(&display_map, Bias::Left);
 3744                let (range, _) = buffer.surrounding_word(position, None);
 3745                start = buffer.anchor_before(range.start);
 3746                end = buffer.anchor_before(range.end);
 3747                mode = SelectMode::Word(start..end);
 3748                auto_scroll = true;
 3749            }
 3750            3 => {
 3751                let position = display_map
 3752                    .clip_point(position, Bias::Left)
 3753                    .to_point(&display_map);
 3754                let line_start = display_map.prev_line_boundary(position).0;
 3755                let next_line_start = buffer.clip_point(
 3756                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3757                    Bias::Left,
 3758                );
 3759                start = buffer.anchor_before(line_start);
 3760                end = buffer.anchor_before(next_line_start);
 3761                mode = SelectMode::Line(start..end);
 3762                auto_scroll = true;
 3763            }
 3764            _ => {
 3765                start = buffer.anchor_before(MultiBufferOffset(0));
 3766                end = buffer.anchor_before(buffer.len());
 3767                mode = SelectMode::All;
 3768                auto_scroll = false;
 3769            }
 3770        }
 3771        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3772
 3773        let point_to_delete: Option<usize> = {
 3774            let selected_points: Vec<Selection<Point>> =
 3775                self.selections.disjoint_in_range(start..end, &display_map);
 3776
 3777            if !add || click_count > 1 {
 3778                None
 3779            } else if !selected_points.is_empty() {
 3780                Some(selected_points[0].id)
 3781            } else {
 3782                let clicked_point_already_selected =
 3783                    self.selections.disjoint_anchors().iter().find(|selection| {
 3784                        selection.start.to_point(buffer) == start.to_point(buffer)
 3785                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3786                    });
 3787
 3788                clicked_point_already_selected.map(|selection| selection.id)
 3789            }
 3790        };
 3791
 3792        let selections_count = self.selections.count();
 3793        let effects = if auto_scroll {
 3794            SelectionEffects::default()
 3795        } else {
 3796            SelectionEffects::no_scroll()
 3797        };
 3798
 3799        self.change_selections(effects, window, cx, |s| {
 3800            if let Some(point_to_delete) = point_to_delete {
 3801                s.delete(point_to_delete);
 3802
 3803                if selections_count == 1 {
 3804                    s.set_pending_anchor_range(start..end, mode);
 3805                }
 3806            } else {
 3807                if !add {
 3808                    s.clear_disjoint();
 3809                }
 3810
 3811                s.set_pending_anchor_range(start..end, mode);
 3812            }
 3813        });
 3814    }
 3815
 3816    fn begin_columnar_selection(
 3817        &mut self,
 3818        position: DisplayPoint,
 3819        goal_column: u32,
 3820        reset: bool,
 3821        mode: ColumnarMode,
 3822        window: &mut Window,
 3823        cx: &mut Context<Self>,
 3824    ) {
 3825        if !self.focus_handle.is_focused(window) {
 3826            self.last_focused_descendant = None;
 3827            window.focus(&self.focus_handle);
 3828        }
 3829
 3830        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3831
 3832        if reset {
 3833            let pointer_position = display_map
 3834                .buffer_snapshot()
 3835                .anchor_before(position.to_point(&display_map));
 3836
 3837            self.change_selections(
 3838                SelectionEffects::scroll(Autoscroll::newest()),
 3839                window,
 3840                cx,
 3841                |s| {
 3842                    s.clear_disjoint();
 3843                    s.set_pending_anchor_range(
 3844                        pointer_position..pointer_position,
 3845                        SelectMode::Character,
 3846                    );
 3847                },
 3848            );
 3849        };
 3850
 3851        let tail = self.selections.newest::<Point>(&display_map).tail();
 3852        let selection_anchor = display_map.buffer_snapshot().anchor_before(tail);
 3853        self.columnar_selection_state = match mode {
 3854            ColumnarMode::FromMouse => Some(ColumnarSelectionState::FromMouse {
 3855                selection_tail: selection_anchor,
 3856                display_point: if reset {
 3857                    if position.column() != goal_column {
 3858                        Some(DisplayPoint::new(position.row(), goal_column))
 3859                    } else {
 3860                        None
 3861                    }
 3862                } else {
 3863                    None
 3864                },
 3865            }),
 3866            ColumnarMode::FromSelection => Some(ColumnarSelectionState::FromSelection {
 3867                selection_tail: selection_anchor,
 3868            }),
 3869        };
 3870
 3871        if !reset {
 3872            self.select_columns(position, goal_column, &display_map, window, cx);
 3873        }
 3874    }
 3875
 3876    fn update_selection(
 3877        &mut self,
 3878        position: DisplayPoint,
 3879        goal_column: u32,
 3880        scroll_delta: gpui::Point<f32>,
 3881        window: &mut Window,
 3882        cx: &mut Context<Self>,
 3883    ) {
 3884        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3885
 3886        if self.columnar_selection_state.is_some() {
 3887            self.select_columns(position, goal_column, &display_map, window, cx);
 3888        } else if let Some(mut pending) = self.selections.pending_anchor().cloned() {
 3889            let buffer = display_map.buffer_snapshot();
 3890            let head;
 3891            let tail;
 3892            let mode = self.selections.pending_mode().unwrap();
 3893            match &mode {
 3894                SelectMode::Character => {
 3895                    head = position.to_point(&display_map);
 3896                    tail = pending.tail().to_point(buffer);
 3897                }
 3898                SelectMode::Word(original_range) => {
 3899                    let offset = display_map
 3900                        .clip_point(position, Bias::Left)
 3901                        .to_offset(&display_map, Bias::Left);
 3902                    let original_range = original_range.to_offset(buffer);
 3903
 3904                    let head_offset = if buffer.is_inside_word(offset, None)
 3905                        || original_range.contains(&offset)
 3906                    {
 3907                        let (word_range, _) = buffer.surrounding_word(offset, None);
 3908                        if word_range.start < original_range.start {
 3909                            word_range.start
 3910                        } else {
 3911                            word_range.end
 3912                        }
 3913                    } else {
 3914                        offset
 3915                    };
 3916
 3917                    head = head_offset.to_point(buffer);
 3918                    if head_offset <= original_range.start {
 3919                        tail = original_range.end.to_point(buffer);
 3920                    } else {
 3921                        tail = original_range.start.to_point(buffer);
 3922                    }
 3923                }
 3924                SelectMode::Line(original_range) => {
 3925                    let original_range = original_range.to_point(display_map.buffer_snapshot());
 3926
 3927                    let position = display_map
 3928                        .clip_point(position, Bias::Left)
 3929                        .to_point(&display_map);
 3930                    let line_start = display_map.prev_line_boundary(position).0;
 3931                    let next_line_start = buffer.clip_point(
 3932                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3933                        Bias::Left,
 3934                    );
 3935
 3936                    if line_start < original_range.start {
 3937                        head = line_start
 3938                    } else {
 3939                        head = next_line_start
 3940                    }
 3941
 3942                    if head <= original_range.start {
 3943                        tail = original_range.end;
 3944                    } else {
 3945                        tail = original_range.start;
 3946                    }
 3947                }
 3948                SelectMode::All => {
 3949                    return;
 3950                }
 3951            };
 3952
 3953            if head < tail {
 3954                pending.start = buffer.anchor_before(head);
 3955                pending.end = buffer.anchor_before(tail);
 3956                pending.reversed = true;
 3957            } else {
 3958                pending.start = buffer.anchor_before(tail);
 3959                pending.end = buffer.anchor_before(head);
 3960                pending.reversed = false;
 3961            }
 3962
 3963            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3964                s.set_pending(pending.clone(), mode);
 3965            });
 3966        } else {
 3967            log::error!("update_selection dispatched with no pending selection");
 3968            return;
 3969        }
 3970
 3971        self.apply_scroll_delta(scroll_delta, window, cx);
 3972        cx.notify();
 3973    }
 3974
 3975    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3976        self.columnar_selection_state.take();
 3977        if let Some(pending_mode) = self.selections.pending_mode() {
 3978            let selections = self
 3979                .selections
 3980                .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 3981            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3982                s.select(selections);
 3983                s.clear_pending();
 3984                if s.is_extending() {
 3985                    s.set_is_extending(false);
 3986                } else {
 3987                    s.set_select_mode(pending_mode);
 3988                }
 3989            });
 3990        }
 3991    }
 3992
 3993    fn select_columns(
 3994        &mut self,
 3995        head: DisplayPoint,
 3996        goal_column: u32,
 3997        display_map: &DisplaySnapshot,
 3998        window: &mut Window,
 3999        cx: &mut Context<Self>,
 4000    ) {
 4001        let Some(columnar_state) = self.columnar_selection_state.as_ref() else {
 4002            return;
 4003        };
 4004
 4005        let tail = match columnar_state {
 4006            ColumnarSelectionState::FromMouse {
 4007                selection_tail,
 4008                display_point,
 4009            } => display_point.unwrap_or_else(|| selection_tail.to_display_point(display_map)),
 4010            ColumnarSelectionState::FromSelection { selection_tail } => {
 4011                selection_tail.to_display_point(display_map)
 4012            }
 4013        };
 4014
 4015        let start_row = cmp::min(tail.row(), head.row());
 4016        let end_row = cmp::max(tail.row(), head.row());
 4017        let start_column = cmp::min(tail.column(), goal_column);
 4018        let end_column = cmp::max(tail.column(), goal_column);
 4019        let reversed = start_column < tail.column();
 4020
 4021        let selection_ranges = (start_row.0..=end_row.0)
 4022            .map(DisplayRow)
 4023            .filter_map(|row| {
 4024                if (matches!(columnar_state, ColumnarSelectionState::FromMouse { .. })
 4025                    || start_column <= display_map.line_len(row))
 4026                    && !display_map.is_block_line(row)
 4027                {
 4028                    let start = display_map
 4029                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 4030                        .to_point(display_map);
 4031                    let end = display_map
 4032                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 4033                        .to_point(display_map);
 4034                    if reversed {
 4035                        Some(end..start)
 4036                    } else {
 4037                        Some(start..end)
 4038                    }
 4039                } else {
 4040                    None
 4041                }
 4042            })
 4043            .collect::<Vec<_>>();
 4044        if selection_ranges.is_empty() {
 4045            return;
 4046        }
 4047
 4048        let ranges = match columnar_state {
 4049            ColumnarSelectionState::FromMouse { .. } => {
 4050                let mut non_empty_ranges = selection_ranges
 4051                    .iter()
 4052                    .filter(|selection_range| selection_range.start != selection_range.end)
 4053                    .peekable();
 4054                if non_empty_ranges.peek().is_some() {
 4055                    non_empty_ranges.cloned().collect()
 4056                } else {
 4057                    selection_ranges
 4058                }
 4059            }
 4060            _ => selection_ranges,
 4061        };
 4062
 4063        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 4064            s.select_ranges(ranges);
 4065        });
 4066        cx.notify();
 4067    }
 4068
 4069    pub fn has_non_empty_selection(&self, snapshot: &DisplaySnapshot) -> bool {
 4070        self.selections
 4071            .all_adjusted(snapshot)
 4072            .iter()
 4073            .any(|selection| !selection.is_empty())
 4074    }
 4075
 4076    pub fn has_pending_nonempty_selection(&self) -> bool {
 4077        let pending_nonempty_selection = match self.selections.pending_anchor() {
 4078            Some(Selection { start, end, .. }) => start != end,
 4079            None => false,
 4080        };
 4081
 4082        pending_nonempty_selection
 4083            || (self.columnar_selection_state.is_some()
 4084                && self.selections.disjoint_anchors().len() > 1)
 4085    }
 4086
 4087    pub fn has_pending_selection(&self) -> bool {
 4088        self.selections.pending_anchor().is_some() || self.columnar_selection_state.is_some()
 4089    }
 4090
 4091    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 4092        self.selection_mark_mode = false;
 4093        self.selection_drag_state = SelectionDragState::None;
 4094
 4095        if self.dismiss_menus_and_popups(true, window, cx) {
 4096            cx.notify();
 4097            return;
 4098        }
 4099        if self.clear_expanded_diff_hunks(cx) {
 4100            cx.notify();
 4101            return;
 4102        }
 4103        if self.show_git_blame_gutter {
 4104            self.show_git_blame_gutter = false;
 4105            cx.notify();
 4106            return;
 4107        }
 4108
 4109        if self.mode.is_full()
 4110            && self.change_selections(Default::default(), window, cx, |s| s.try_cancel())
 4111        {
 4112            cx.notify();
 4113            return;
 4114        }
 4115
 4116        cx.propagate();
 4117    }
 4118
 4119    pub fn dismiss_menus_and_popups(
 4120        &mut self,
 4121        is_user_requested: bool,
 4122        window: &mut Window,
 4123        cx: &mut Context<Self>,
 4124    ) -> bool {
 4125        if self.take_rename(false, window, cx).is_some() {
 4126            return true;
 4127        }
 4128
 4129        if self.hide_blame_popover(true, cx) {
 4130            return true;
 4131        }
 4132
 4133        if hide_hover(self, cx) {
 4134            return true;
 4135        }
 4136
 4137        if self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape) {
 4138            return true;
 4139        }
 4140
 4141        if self.hide_context_menu(window, cx).is_some() {
 4142            return true;
 4143        }
 4144
 4145        if self.mouse_context_menu.take().is_some() {
 4146            return true;
 4147        }
 4148
 4149        if is_user_requested && self.discard_edit_prediction(true, cx) {
 4150            return true;
 4151        }
 4152
 4153        if self.snippet_stack.pop().is_some() {
 4154            return true;
 4155        }
 4156
 4157        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 4158            self.dismiss_diagnostics(cx);
 4159            return true;
 4160        }
 4161
 4162        false
 4163    }
 4164
 4165    fn linked_editing_ranges_for(
 4166        &self,
 4167        selection: Range<text::Anchor>,
 4168        cx: &App,
 4169    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 4170        if self.linked_edit_ranges.is_empty() {
 4171            return None;
 4172        }
 4173        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 4174            selection.end.buffer_id.and_then(|end_buffer_id| {
 4175                if selection.start.buffer_id != Some(end_buffer_id) {
 4176                    return None;
 4177                }
 4178                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 4179                let snapshot = buffer.read(cx).snapshot();
 4180                self.linked_edit_ranges
 4181                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 4182                    .map(|ranges| (ranges, snapshot, buffer))
 4183            })?;
 4184        use text::ToOffset as TO;
 4185        // find offset from the start of current range to current cursor position
 4186        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 4187
 4188        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 4189        let start_difference = start_offset - start_byte_offset;
 4190        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 4191        let end_difference = end_offset - start_byte_offset;
 4192        // Current range has associated linked ranges.
 4193        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4194        for range in linked_ranges.iter() {
 4195            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 4196            let end_offset = start_offset + end_difference;
 4197            let start_offset = start_offset + start_difference;
 4198            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 4199                continue;
 4200            }
 4201            if self.selections.disjoint_anchor_ranges().any(|s| {
 4202                if s.start.buffer_id != selection.start.buffer_id
 4203                    || s.end.buffer_id != selection.end.buffer_id
 4204                {
 4205                    return false;
 4206                }
 4207                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 4208                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 4209            }) {
 4210                continue;
 4211            }
 4212            let start = buffer_snapshot.anchor_after(start_offset);
 4213            let end = buffer_snapshot.anchor_after(end_offset);
 4214            linked_edits
 4215                .entry(buffer.clone())
 4216                .or_default()
 4217                .push(start..end);
 4218        }
 4219        Some(linked_edits)
 4220    }
 4221
 4222    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4223        let text: Arc<str> = text.into();
 4224
 4225        if self.read_only(cx) {
 4226            return;
 4227        }
 4228
 4229        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4230
 4231        self.unfold_buffers_with_selections(cx);
 4232
 4233        let selections = self.selections.all_adjusted(&self.display_snapshot(cx));
 4234        let mut bracket_inserted = false;
 4235        let mut edits = Vec::new();
 4236        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4237        let mut new_selections = Vec::with_capacity(selections.len());
 4238        let mut new_autoclose_regions = Vec::new();
 4239        let snapshot = self.buffer.read(cx).read(cx);
 4240        let mut clear_linked_edit_ranges = false;
 4241
 4242        for (selection, autoclose_region) in
 4243            self.selections_with_autoclose_regions(selections, &snapshot)
 4244        {
 4245            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 4246                // Determine if the inserted text matches the opening or closing
 4247                // bracket of any of this language's bracket pairs.
 4248                let mut bracket_pair = None;
 4249                let mut is_bracket_pair_start = false;
 4250                let mut is_bracket_pair_end = false;
 4251                if !text.is_empty() {
 4252                    let mut bracket_pair_matching_end = None;
 4253                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 4254                    //  and they are removing the character that triggered IME popup.
 4255                    for (pair, enabled) in scope.brackets() {
 4256                        if !pair.close && !pair.surround {
 4257                            continue;
 4258                        }
 4259
 4260                        if enabled && pair.start.ends_with(text.as_ref()) {
 4261                            let prefix_len = pair.start.len() - text.len();
 4262                            let preceding_text_matches_prefix = prefix_len == 0
 4263                                || (selection.start.column >= (prefix_len as u32)
 4264                                    && snapshot.contains_str_at(
 4265                                        Point::new(
 4266                                            selection.start.row,
 4267                                            selection.start.column - (prefix_len as u32),
 4268                                        ),
 4269                                        &pair.start[..prefix_len],
 4270                                    ));
 4271                            if preceding_text_matches_prefix {
 4272                                bracket_pair = Some(pair.clone());
 4273                                is_bracket_pair_start = true;
 4274                                break;
 4275                            }
 4276                        }
 4277                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 4278                        {
 4279                            // take first bracket pair matching end, but don't break in case a later bracket
 4280                            // pair matches start
 4281                            bracket_pair_matching_end = Some(pair.clone());
 4282                        }
 4283                    }
 4284                    if let Some(end) = bracket_pair_matching_end
 4285                        && bracket_pair.is_none()
 4286                    {
 4287                        bracket_pair = Some(end);
 4288                        is_bracket_pair_end = true;
 4289                    }
 4290                }
 4291
 4292                if let Some(bracket_pair) = bracket_pair {
 4293                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 4294                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 4295                    let auto_surround =
 4296                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 4297                    if selection.is_empty() {
 4298                        if is_bracket_pair_start {
 4299                            // If the inserted text is a suffix of an opening bracket and the
 4300                            // selection is preceded by the rest of the opening bracket, then
 4301                            // insert the closing bracket.
 4302                            let following_text_allows_autoclose = snapshot
 4303                                .chars_at(selection.start)
 4304                                .next()
 4305                                .is_none_or(|c| scope.should_autoclose_before(c));
 4306
 4307                            let preceding_text_allows_autoclose = selection.start.column == 0
 4308                                || snapshot
 4309                                    .reversed_chars_at(selection.start)
 4310                                    .next()
 4311                                    .is_none_or(|c| {
 4312                                        bracket_pair.start != bracket_pair.end
 4313                                            || !snapshot
 4314                                                .char_classifier_at(selection.start)
 4315                                                .is_word(c)
 4316                                    });
 4317
 4318                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 4319                                && bracket_pair.start.len() == 1
 4320                            {
 4321                                let target = bracket_pair.start.chars().next().unwrap();
 4322                                let current_line_count = snapshot
 4323                                    .reversed_chars_at(selection.start)
 4324                                    .take_while(|&c| c != '\n')
 4325                                    .filter(|&c| c == target)
 4326                                    .count();
 4327                                current_line_count % 2 == 1
 4328                            } else {
 4329                                false
 4330                            };
 4331
 4332                            if autoclose
 4333                                && bracket_pair.close
 4334                                && following_text_allows_autoclose
 4335                                && preceding_text_allows_autoclose
 4336                                && !is_closing_quote
 4337                            {
 4338                                let anchor = snapshot.anchor_before(selection.end);
 4339                                new_selections.push((selection.map(|_| anchor), text.len()));
 4340                                new_autoclose_regions.push((
 4341                                    anchor,
 4342                                    text.len(),
 4343                                    selection.id,
 4344                                    bracket_pair.clone(),
 4345                                ));
 4346                                edits.push((
 4347                                    selection.range(),
 4348                                    format!("{}{}", text, bracket_pair.end).into(),
 4349                                ));
 4350                                bracket_inserted = true;
 4351                                continue;
 4352                            }
 4353                        }
 4354
 4355                        if let Some(region) = autoclose_region {
 4356                            // If the selection is followed by an auto-inserted closing bracket,
 4357                            // then don't insert that closing bracket again; just move the selection
 4358                            // past the closing bracket.
 4359                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 4360                                && text.as_ref() == region.pair.end.as_str()
 4361                                && snapshot.contains_str_at(region.range.end, text.as_ref());
 4362                            if should_skip {
 4363                                let anchor = snapshot.anchor_after(selection.end);
 4364                                new_selections
 4365                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 4366                                continue;
 4367                            }
 4368                        }
 4369
 4370                        let always_treat_brackets_as_autoclosed = snapshot
 4371                            .language_settings_at(selection.start, cx)
 4372                            .always_treat_brackets_as_autoclosed;
 4373                        if always_treat_brackets_as_autoclosed
 4374                            && is_bracket_pair_end
 4375                            && snapshot.contains_str_at(selection.end, text.as_ref())
 4376                        {
 4377                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 4378                            // and the inserted text is a closing bracket and the selection is followed
 4379                            // by the closing bracket then move the selection past the closing bracket.
 4380                            let anchor = snapshot.anchor_after(selection.end);
 4381                            new_selections.push((selection.map(|_| anchor), text.len()));
 4382                            continue;
 4383                        }
 4384                    }
 4385                    // If an opening bracket is 1 character long and is typed while
 4386                    // text is selected, then surround that text with the bracket pair.
 4387                    else if auto_surround
 4388                        && bracket_pair.surround
 4389                        && is_bracket_pair_start
 4390                        && bracket_pair.start.chars().count() == 1
 4391                    {
 4392                        edits.push((selection.start..selection.start, text.clone()));
 4393                        edits.push((
 4394                            selection.end..selection.end,
 4395                            bracket_pair.end.as_str().into(),
 4396                        ));
 4397                        bracket_inserted = true;
 4398                        new_selections.push((
 4399                            Selection {
 4400                                id: selection.id,
 4401                                start: snapshot.anchor_after(selection.start),
 4402                                end: snapshot.anchor_before(selection.end),
 4403                                reversed: selection.reversed,
 4404                                goal: selection.goal,
 4405                            },
 4406                            0,
 4407                        ));
 4408                        continue;
 4409                    }
 4410                }
 4411            }
 4412
 4413            if self.auto_replace_emoji_shortcode
 4414                && selection.is_empty()
 4415                && text.as_ref().ends_with(':')
 4416                && let Some(possible_emoji_short_code) =
 4417                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 4418                && !possible_emoji_short_code.is_empty()
 4419                && let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code)
 4420            {
 4421                let emoji_shortcode_start = Point::new(
 4422                    selection.start.row,
 4423                    selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 4424                );
 4425
 4426                // Remove shortcode from buffer
 4427                edits.push((
 4428                    emoji_shortcode_start..selection.start,
 4429                    "".to_string().into(),
 4430                ));
 4431                new_selections.push((
 4432                    Selection {
 4433                        id: selection.id,
 4434                        start: snapshot.anchor_after(emoji_shortcode_start),
 4435                        end: snapshot.anchor_before(selection.start),
 4436                        reversed: selection.reversed,
 4437                        goal: selection.goal,
 4438                    },
 4439                    0,
 4440                ));
 4441
 4442                // Insert emoji
 4443                let selection_start_anchor = snapshot.anchor_after(selection.start);
 4444                new_selections.push((selection.map(|_| selection_start_anchor), 0));
 4445                edits.push((selection.start..selection.end, emoji.to_string().into()));
 4446
 4447                continue;
 4448            }
 4449
 4450            // If not handling any auto-close operation, then just replace the selected
 4451            // text with the given input and move the selection to the end of the
 4452            // newly inserted text.
 4453            let anchor = snapshot.anchor_after(selection.end);
 4454            if !self.linked_edit_ranges.is_empty() {
 4455                let start_anchor = snapshot.anchor_before(selection.start);
 4456
 4457                let is_word_char = text.chars().next().is_none_or(|char| {
 4458                    let classifier = snapshot
 4459                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 4460                        .scope_context(Some(CharScopeContext::LinkedEdit));
 4461                    classifier.is_word(char)
 4462                });
 4463
 4464                if is_word_char {
 4465                    if let Some(ranges) = self
 4466                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 4467                    {
 4468                        for (buffer, edits) in ranges {
 4469                            linked_edits
 4470                                .entry(buffer.clone())
 4471                                .or_default()
 4472                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 4473                        }
 4474                    }
 4475                } else {
 4476                    clear_linked_edit_ranges = true;
 4477                }
 4478            }
 4479
 4480            new_selections.push((selection.map(|_| anchor), 0));
 4481            edits.push((selection.start..selection.end, text.clone()));
 4482        }
 4483
 4484        drop(snapshot);
 4485
 4486        self.transact(window, cx, |this, window, cx| {
 4487            if clear_linked_edit_ranges {
 4488                this.linked_edit_ranges.clear();
 4489            }
 4490            let initial_buffer_versions =
 4491                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 4492
 4493            this.buffer.update(cx, |buffer, cx| {
 4494                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 4495            });
 4496            for (buffer, edits) in linked_edits {
 4497                buffer.update(cx, |buffer, cx| {
 4498                    let snapshot = buffer.snapshot();
 4499                    let edits = edits
 4500                        .into_iter()
 4501                        .map(|(range, text)| {
 4502                            use text::ToPoint as TP;
 4503                            let end_point = TP::to_point(&range.end, &snapshot);
 4504                            let start_point = TP::to_point(&range.start, &snapshot);
 4505                            (start_point..end_point, text)
 4506                        })
 4507                        .sorted_by_key(|(range, _)| range.start);
 4508                    buffer.edit(edits, None, cx);
 4509                })
 4510            }
 4511            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 4512            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 4513            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 4514            let new_selections = resolve_selections_wrapping_blocks::<MultiBufferOffset, _>(
 4515                new_anchor_selections,
 4516                &map,
 4517            )
 4518            .zip(new_selection_deltas)
 4519            .map(|(selection, delta)| Selection {
 4520                id: selection.id,
 4521                start: selection.start + delta,
 4522                end: selection.end + delta,
 4523                reversed: selection.reversed,
 4524                goal: SelectionGoal::None,
 4525            })
 4526            .collect::<Vec<_>>();
 4527
 4528            let mut i = 0;
 4529            for (position, delta, selection_id, pair) in new_autoclose_regions {
 4530                let position = position.to_offset(map.buffer_snapshot()) + delta;
 4531                let start = map.buffer_snapshot().anchor_before(position);
 4532                let end = map.buffer_snapshot().anchor_after(position);
 4533                while let Some(existing_state) = this.autoclose_regions.get(i) {
 4534                    match existing_state
 4535                        .range
 4536                        .start
 4537                        .cmp(&start, map.buffer_snapshot())
 4538                    {
 4539                        Ordering::Less => i += 1,
 4540                        Ordering::Greater => break,
 4541                        Ordering::Equal => {
 4542                            match end.cmp(&existing_state.range.end, map.buffer_snapshot()) {
 4543                                Ordering::Less => i += 1,
 4544                                Ordering::Equal => break,
 4545                                Ordering::Greater => break,
 4546                            }
 4547                        }
 4548                    }
 4549                }
 4550                this.autoclose_regions.insert(
 4551                    i,
 4552                    AutocloseRegion {
 4553                        selection_id,
 4554                        range: start..end,
 4555                        pair,
 4556                    },
 4557                );
 4558            }
 4559
 4560            let had_active_edit_prediction = this.has_active_edit_prediction();
 4561            this.change_selections(
 4562                SelectionEffects::scroll(Autoscroll::fit()).completions(false),
 4563                window,
 4564                cx,
 4565                |s| s.select(new_selections),
 4566            );
 4567
 4568            if !bracket_inserted
 4569                && let Some(on_type_format_task) =
 4570                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 4571            {
 4572                on_type_format_task.detach_and_log_err(cx);
 4573            }
 4574
 4575            let editor_settings = EditorSettings::get_global(cx);
 4576            if bracket_inserted
 4577                && (editor_settings.auto_signature_help
 4578                    || editor_settings.show_signature_help_after_edits)
 4579            {
 4580                this.show_signature_help(&ShowSignatureHelp, window, cx);
 4581            }
 4582
 4583            let trigger_in_words =
 4584                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
 4585            if this.hard_wrap.is_some() {
 4586                let latest: Range<Point> = this.selections.newest(&map).range();
 4587                if latest.is_empty()
 4588                    && this
 4589                        .buffer()
 4590                        .read(cx)
 4591                        .snapshot(cx)
 4592                        .line_len(MultiBufferRow(latest.start.row))
 4593                        == latest.start.column
 4594                {
 4595                    this.rewrap_impl(
 4596                        RewrapOptions {
 4597                            override_language_settings: true,
 4598                            preserve_existing_whitespace: true,
 4599                        },
 4600                        cx,
 4601                    )
 4602                }
 4603            }
 4604            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4605            refresh_linked_ranges(this, window, cx);
 4606            this.refresh_edit_prediction(true, false, window, cx);
 4607            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4608        });
 4609    }
 4610
 4611    fn find_possible_emoji_shortcode_at_position(
 4612        snapshot: &MultiBufferSnapshot,
 4613        position: Point,
 4614    ) -> Option<String> {
 4615        let mut chars = Vec::new();
 4616        let mut found_colon = false;
 4617        for char in snapshot.reversed_chars_at(position).take(100) {
 4618            // Found a possible emoji shortcode in the middle of the buffer
 4619            if found_colon {
 4620                if char.is_whitespace() {
 4621                    chars.reverse();
 4622                    return Some(chars.iter().collect());
 4623                }
 4624                // If the previous character is not a whitespace, we are in the middle of a word
 4625                // and we only want to complete the shortcode if the word is made up of other emojis
 4626                let mut containing_word = String::new();
 4627                for ch in snapshot
 4628                    .reversed_chars_at(position)
 4629                    .skip(chars.len() + 1)
 4630                    .take(100)
 4631                {
 4632                    if ch.is_whitespace() {
 4633                        break;
 4634                    }
 4635                    containing_word.push(ch);
 4636                }
 4637                let containing_word = containing_word.chars().rev().collect::<String>();
 4638                if util::word_consists_of_emojis(containing_word.as_str()) {
 4639                    chars.reverse();
 4640                    return Some(chars.iter().collect());
 4641                }
 4642            }
 4643
 4644            if char.is_whitespace() || !char.is_ascii() {
 4645                return None;
 4646            }
 4647            if char == ':' {
 4648                found_colon = true;
 4649            } else {
 4650                chars.push(char);
 4651            }
 4652        }
 4653        // Found a possible emoji shortcode at the beginning of the buffer
 4654        chars.reverse();
 4655        Some(chars.iter().collect())
 4656    }
 4657
 4658    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4659        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4660        self.transact(window, cx, |this, window, cx| {
 4661            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4662                let selections = this
 4663                    .selections
 4664                    .all::<MultiBufferOffset>(&this.display_snapshot(cx));
 4665                let multi_buffer = this.buffer.read(cx);
 4666                let buffer = multi_buffer.snapshot(cx);
 4667                selections
 4668                    .iter()
 4669                    .map(|selection| {
 4670                        let start_point = selection.start.to_point(&buffer);
 4671                        let mut existing_indent =
 4672                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4673                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4674                        let start = selection.start;
 4675                        let end = selection.end;
 4676                        let selection_is_empty = start == end;
 4677                        let language_scope = buffer.language_scope_at(start);
 4678                        let (
 4679                            comment_delimiter,
 4680                            doc_delimiter,
 4681                            insert_extra_newline,
 4682                            indent_on_newline,
 4683                            indent_on_extra_newline,
 4684                        ) = if let Some(language) = &language_scope {
 4685                            let mut insert_extra_newline =
 4686                                insert_extra_newline_brackets(&buffer, start..end, language)
 4687                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 4688
 4689                            // Comment extension on newline is allowed only for cursor selections
 4690                            let comment_delimiter = maybe!({
 4691                                if !selection_is_empty {
 4692                                    return None;
 4693                                }
 4694
 4695                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4696                                    return None;
 4697                                }
 4698
 4699                                let delimiters = language.line_comment_prefixes();
 4700                                let max_len_of_delimiter =
 4701                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 4702                                let (snapshot, range) =
 4703                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4704
 4705                                let num_of_whitespaces = snapshot
 4706                                    .chars_for_range(range.clone())
 4707                                    .take_while(|c| c.is_whitespace())
 4708                                    .count();
 4709                                let comment_candidate = snapshot
 4710                                    .chars_for_range(range.clone())
 4711                                    .skip(num_of_whitespaces)
 4712                                    .take(max_len_of_delimiter)
 4713                                    .collect::<String>();
 4714                                let (delimiter, trimmed_len) = delimiters
 4715                                    .iter()
 4716                                    .filter_map(|delimiter| {
 4717                                        let prefix = delimiter.trim_end();
 4718                                        if comment_candidate.starts_with(prefix) {
 4719                                            Some((delimiter, prefix.len()))
 4720                                        } else {
 4721                                            None
 4722                                        }
 4723                                    })
 4724                                    .max_by_key(|(_, len)| *len)?;
 4725
 4726                                if let Some(BlockCommentConfig {
 4727                                    start: block_start, ..
 4728                                }) = language.block_comment()
 4729                                {
 4730                                    let block_start_trimmed = block_start.trim_end();
 4731                                    if block_start_trimmed.starts_with(delimiter.trim_end()) {
 4732                                        let line_content = snapshot
 4733                                            .chars_for_range(range)
 4734                                            .skip(num_of_whitespaces)
 4735                                            .take(block_start_trimmed.len())
 4736                                            .collect::<String>();
 4737
 4738                                        if line_content.starts_with(block_start_trimmed) {
 4739                                            return None;
 4740                                        }
 4741                                    }
 4742                                }
 4743
 4744                                let cursor_is_placed_after_comment_marker =
 4745                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 4746                                if cursor_is_placed_after_comment_marker {
 4747                                    Some(delimiter.clone())
 4748                                } else {
 4749                                    None
 4750                                }
 4751                            });
 4752
 4753                            let mut indent_on_newline = IndentSize::spaces(0);
 4754                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 4755
 4756                            let doc_delimiter = maybe!({
 4757                                if !selection_is_empty {
 4758                                    return None;
 4759                                }
 4760
 4761                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4762                                    return None;
 4763                                }
 4764
 4765                                let BlockCommentConfig {
 4766                                    start: start_tag,
 4767                                    end: end_tag,
 4768                                    prefix: delimiter,
 4769                                    tab_size: len,
 4770                                } = language.documentation_comment()?;
 4771                                let is_within_block_comment = buffer
 4772                                    .language_scope_at(start_point)
 4773                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4774                                if !is_within_block_comment {
 4775                                    return None;
 4776                                }
 4777
 4778                                let (snapshot, range) =
 4779                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4780
 4781                                let num_of_whitespaces = snapshot
 4782                                    .chars_for_range(range.clone())
 4783                                    .take_while(|c| c.is_whitespace())
 4784                                    .count();
 4785
 4786                                // 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.
 4787                                let column = start_point.column;
 4788                                let cursor_is_after_start_tag = {
 4789                                    let start_tag_len = start_tag.len();
 4790                                    let start_tag_line = snapshot
 4791                                        .chars_for_range(range.clone())
 4792                                        .skip(num_of_whitespaces)
 4793                                        .take(start_tag_len)
 4794                                        .collect::<String>();
 4795                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4796                                        num_of_whitespaces + start_tag_len <= column as usize
 4797                                    } else {
 4798                                        false
 4799                                    }
 4800                                };
 4801
 4802                                let cursor_is_after_delimiter = {
 4803                                    let delimiter_trim = delimiter.trim_end();
 4804                                    let delimiter_line = snapshot
 4805                                        .chars_for_range(range.clone())
 4806                                        .skip(num_of_whitespaces)
 4807                                        .take(delimiter_trim.len())
 4808                                        .collect::<String>();
 4809                                    if delimiter_line.starts_with(delimiter_trim) {
 4810                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4811                                    } else {
 4812                                        false
 4813                                    }
 4814                                };
 4815
 4816                                let cursor_is_before_end_tag_if_exists = {
 4817                                    let mut char_position = 0u32;
 4818                                    let mut end_tag_offset = None;
 4819
 4820                                    'outer: for chunk in snapshot.text_for_range(range) {
 4821                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4822                                            let chars_before_match =
 4823                                                chunk[..byte_pos].chars().count() as u32;
 4824                                            end_tag_offset =
 4825                                                Some(char_position + chars_before_match);
 4826                                            break 'outer;
 4827                                        }
 4828                                        char_position += chunk.chars().count() as u32;
 4829                                    }
 4830
 4831                                    if let Some(end_tag_offset) = end_tag_offset {
 4832                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4833                                        if cursor_is_after_start_tag {
 4834                                            if cursor_is_before_end_tag {
 4835                                                insert_extra_newline = true;
 4836                                            }
 4837                                            let cursor_is_at_start_of_end_tag =
 4838                                                column == end_tag_offset;
 4839                                            if cursor_is_at_start_of_end_tag {
 4840                                                indent_on_extra_newline.len = *len;
 4841                                            }
 4842                                        }
 4843                                        cursor_is_before_end_tag
 4844                                    } else {
 4845                                        true
 4846                                    }
 4847                                };
 4848
 4849                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4850                                    && cursor_is_before_end_tag_if_exists
 4851                                {
 4852                                    if cursor_is_after_start_tag {
 4853                                        indent_on_newline.len = *len;
 4854                                    }
 4855                                    Some(delimiter.clone())
 4856                                } else {
 4857                                    None
 4858                                }
 4859                            });
 4860
 4861                            (
 4862                                comment_delimiter,
 4863                                doc_delimiter,
 4864                                insert_extra_newline,
 4865                                indent_on_newline,
 4866                                indent_on_extra_newline,
 4867                            )
 4868                        } else {
 4869                            (
 4870                                None,
 4871                                None,
 4872                                false,
 4873                                IndentSize::default(),
 4874                                IndentSize::default(),
 4875                            )
 4876                        };
 4877
 4878                        let prevent_auto_indent = doc_delimiter.is_some();
 4879                        let delimiter = comment_delimiter.or(doc_delimiter);
 4880
 4881                        let capacity_for_delimiter =
 4882                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4883                        let mut new_text = String::with_capacity(
 4884                            1 + capacity_for_delimiter
 4885                                + existing_indent.len as usize
 4886                                + indent_on_newline.len as usize
 4887                                + indent_on_extra_newline.len as usize,
 4888                        );
 4889                        new_text.push('\n');
 4890                        new_text.extend(existing_indent.chars());
 4891                        new_text.extend(indent_on_newline.chars());
 4892
 4893                        if let Some(delimiter) = &delimiter {
 4894                            new_text.push_str(delimiter);
 4895                        }
 4896
 4897                        if insert_extra_newline {
 4898                            new_text.push('\n');
 4899                            new_text.extend(existing_indent.chars());
 4900                            new_text.extend(indent_on_extra_newline.chars());
 4901                        }
 4902
 4903                        let anchor = buffer.anchor_after(end);
 4904                        let new_selection = selection.map(|_| anchor);
 4905                        (
 4906                            ((start..end, new_text), prevent_auto_indent),
 4907                            (insert_extra_newline, new_selection),
 4908                        )
 4909                    })
 4910                    .unzip()
 4911            };
 4912
 4913            let mut auto_indent_edits = Vec::new();
 4914            let mut edits = Vec::new();
 4915            for (edit, prevent_auto_indent) in edits_with_flags {
 4916                if prevent_auto_indent {
 4917                    edits.push(edit);
 4918                } else {
 4919                    auto_indent_edits.push(edit);
 4920                }
 4921            }
 4922            if !edits.is_empty() {
 4923                this.edit(edits, cx);
 4924            }
 4925            if !auto_indent_edits.is_empty() {
 4926                this.edit_with_autoindent(auto_indent_edits, cx);
 4927            }
 4928
 4929            let buffer = this.buffer.read(cx).snapshot(cx);
 4930            let new_selections = selection_info
 4931                .into_iter()
 4932                .map(|(extra_newline_inserted, new_selection)| {
 4933                    let mut cursor = new_selection.end.to_point(&buffer);
 4934                    if extra_newline_inserted {
 4935                        cursor.row -= 1;
 4936                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4937                    }
 4938                    new_selection.map(|_| cursor)
 4939                })
 4940                .collect();
 4941
 4942            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
 4943            this.refresh_edit_prediction(true, false, window, cx);
 4944        });
 4945    }
 4946
 4947    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4948        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4949
 4950        let buffer = self.buffer.read(cx);
 4951        let snapshot = buffer.snapshot(cx);
 4952
 4953        let mut edits = Vec::new();
 4954        let mut rows = Vec::new();
 4955
 4956        for (rows_inserted, selection) in self
 4957            .selections
 4958            .all_adjusted(&self.display_snapshot(cx))
 4959            .into_iter()
 4960            .enumerate()
 4961        {
 4962            let cursor = selection.head();
 4963            let row = cursor.row;
 4964
 4965            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4966
 4967            let newline = "\n".to_string();
 4968            edits.push((start_of_line..start_of_line, newline));
 4969
 4970            rows.push(row + rows_inserted as u32);
 4971        }
 4972
 4973        self.transact(window, cx, |editor, window, cx| {
 4974            editor.edit(edits, cx);
 4975
 4976            editor.change_selections(Default::default(), window, cx, |s| {
 4977                let mut index = 0;
 4978                s.move_cursors_with(|map, _, _| {
 4979                    let row = rows[index];
 4980                    index += 1;
 4981
 4982                    let point = Point::new(row, 0);
 4983                    let boundary = map.next_line_boundary(point).1;
 4984                    let clipped = map.clip_point(boundary, Bias::Left);
 4985
 4986                    (clipped, SelectionGoal::None)
 4987                });
 4988            });
 4989
 4990            let mut indent_edits = Vec::new();
 4991            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4992            for row in rows {
 4993                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4994                for (row, indent) in indents {
 4995                    if indent.len == 0 {
 4996                        continue;
 4997                    }
 4998
 4999                    let text = match indent.kind {
 5000                        IndentKind::Space => " ".repeat(indent.len as usize),
 5001                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 5002                    };
 5003                    let point = Point::new(row.0, 0);
 5004                    indent_edits.push((point..point, text));
 5005                }
 5006            }
 5007            editor.edit(indent_edits, cx);
 5008        });
 5009    }
 5010
 5011    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 5012        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5013
 5014        let buffer = self.buffer.read(cx);
 5015        let snapshot = buffer.snapshot(cx);
 5016
 5017        let mut edits = Vec::new();
 5018        let mut rows = Vec::new();
 5019        let mut rows_inserted = 0;
 5020
 5021        for selection in self.selections.all_adjusted(&self.display_snapshot(cx)) {
 5022            let cursor = selection.head();
 5023            let row = cursor.row;
 5024
 5025            let point = Point::new(row + 1, 0);
 5026            let start_of_line = snapshot.clip_point(point, Bias::Left);
 5027
 5028            let newline = "\n".to_string();
 5029            edits.push((start_of_line..start_of_line, newline));
 5030
 5031            rows_inserted += 1;
 5032            rows.push(row + rows_inserted);
 5033        }
 5034
 5035        self.transact(window, cx, |editor, window, cx| {
 5036            editor.edit(edits, cx);
 5037
 5038            editor.change_selections(Default::default(), window, cx, |s| {
 5039                let mut index = 0;
 5040                s.move_cursors_with(|map, _, _| {
 5041                    let row = rows[index];
 5042                    index += 1;
 5043
 5044                    let point = Point::new(row, 0);
 5045                    let boundary = map.next_line_boundary(point).1;
 5046                    let clipped = map.clip_point(boundary, Bias::Left);
 5047
 5048                    (clipped, SelectionGoal::None)
 5049                });
 5050            });
 5051
 5052            let mut indent_edits = Vec::new();
 5053            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 5054            for row in rows {
 5055                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 5056                for (row, indent) in indents {
 5057                    if indent.len == 0 {
 5058                        continue;
 5059                    }
 5060
 5061                    let text = match indent.kind {
 5062                        IndentKind::Space => " ".repeat(indent.len as usize),
 5063                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 5064                    };
 5065                    let point = Point::new(row.0, 0);
 5066                    indent_edits.push((point..point, text));
 5067                }
 5068            }
 5069            editor.edit(indent_edits, cx);
 5070        });
 5071    }
 5072
 5073    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 5074        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 5075            original_indent_columns: Vec::new(),
 5076        });
 5077        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 5078    }
 5079
 5080    fn insert_with_autoindent_mode(
 5081        &mut self,
 5082        text: &str,
 5083        autoindent_mode: Option<AutoindentMode>,
 5084        window: &mut Window,
 5085        cx: &mut Context<Self>,
 5086    ) {
 5087        if self.read_only(cx) {
 5088            return;
 5089        }
 5090
 5091        let text: Arc<str> = text.into();
 5092        self.transact(window, cx, |this, window, cx| {
 5093            let old_selections = this.selections.all_adjusted(&this.display_snapshot(cx));
 5094            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 5095                let anchors = {
 5096                    let snapshot = buffer.read(cx);
 5097                    old_selections
 5098                        .iter()
 5099                        .map(|s| {
 5100                            let anchor = snapshot.anchor_after(s.head());
 5101                            s.map(|_| anchor)
 5102                        })
 5103                        .collect::<Vec<_>>()
 5104                };
 5105                buffer.edit(
 5106                    old_selections
 5107                        .iter()
 5108                        .map(|s| (s.start..s.end, text.clone())),
 5109                    autoindent_mode,
 5110                    cx,
 5111                );
 5112                anchors
 5113            });
 5114
 5115            this.change_selections(Default::default(), window, cx, |s| {
 5116                s.select_anchors(selection_anchors);
 5117            });
 5118
 5119            cx.notify();
 5120        });
 5121    }
 5122
 5123    fn trigger_completion_on_input(
 5124        &mut self,
 5125        text: &str,
 5126        trigger_in_words: bool,
 5127        window: &mut Window,
 5128        cx: &mut Context<Self>,
 5129    ) {
 5130        let completions_source = self
 5131            .context_menu
 5132            .borrow()
 5133            .as_ref()
 5134            .and_then(|menu| match menu {
 5135                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 5136                CodeContextMenu::CodeActions(_) => None,
 5137            });
 5138
 5139        match completions_source {
 5140            Some(CompletionsMenuSource::Words { .. }) => {
 5141                self.open_or_update_completions_menu(
 5142                    Some(CompletionsMenuSource::Words {
 5143                        ignore_threshold: false,
 5144                    }),
 5145                    None,
 5146                    trigger_in_words,
 5147                    window,
 5148                    cx,
 5149                );
 5150            }
 5151            _ => self.open_or_update_completions_menu(
 5152                None,
 5153                Some(text.to_owned()).filter(|x| !x.is_empty()),
 5154                true,
 5155                window,
 5156                cx,
 5157            ),
 5158        }
 5159    }
 5160
 5161    /// If any empty selections is touching the start of its innermost containing autoclose
 5162    /// region, expand it to select the brackets.
 5163    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 5164        let selections = self
 5165            .selections
 5166            .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 5167        let buffer = self.buffer.read(cx).read(cx);
 5168        let new_selections = self
 5169            .selections_with_autoclose_regions(selections, &buffer)
 5170            .map(|(mut selection, region)| {
 5171                if !selection.is_empty() {
 5172                    return selection;
 5173                }
 5174
 5175                if let Some(region) = region {
 5176                    let mut range = region.range.to_offset(&buffer);
 5177                    if selection.start == range.start && range.start.0 >= region.pair.start.len() {
 5178                        range.start -= region.pair.start.len();
 5179                        if buffer.contains_str_at(range.start, &region.pair.start)
 5180                            && buffer.contains_str_at(range.end, &region.pair.end)
 5181                        {
 5182                            range.end += region.pair.end.len();
 5183                            selection.start = range.start;
 5184                            selection.end = range.end;
 5185
 5186                            return selection;
 5187                        }
 5188                    }
 5189                }
 5190
 5191                let always_treat_brackets_as_autoclosed = buffer
 5192                    .language_settings_at(selection.start, cx)
 5193                    .always_treat_brackets_as_autoclosed;
 5194
 5195                if !always_treat_brackets_as_autoclosed {
 5196                    return selection;
 5197                }
 5198
 5199                if let Some(scope) = buffer.language_scope_at(selection.start) {
 5200                    for (pair, enabled) in scope.brackets() {
 5201                        if !enabled || !pair.close {
 5202                            continue;
 5203                        }
 5204
 5205                        if buffer.contains_str_at(selection.start, &pair.end) {
 5206                            let pair_start_len = pair.start.len();
 5207                            if buffer.contains_str_at(
 5208                                selection.start.saturating_sub_usize(pair_start_len),
 5209                                &pair.start,
 5210                            ) {
 5211                                selection.start -= pair_start_len;
 5212                                selection.end += pair.end.len();
 5213
 5214                                return selection;
 5215                            }
 5216                        }
 5217                    }
 5218                }
 5219
 5220                selection
 5221            })
 5222            .collect();
 5223
 5224        drop(buffer);
 5225        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
 5226            selections.select(new_selections)
 5227        });
 5228    }
 5229
 5230    /// Iterate the given selections, and for each one, find the smallest surrounding
 5231    /// autoclose region. This uses the ordering of the selections and the autoclose
 5232    /// regions to avoid repeated comparisons.
 5233    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 5234        &'a self,
 5235        selections: impl IntoIterator<Item = Selection<D>>,
 5236        buffer: &'a MultiBufferSnapshot,
 5237    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 5238        let mut i = 0;
 5239        let mut regions = self.autoclose_regions.as_slice();
 5240        selections.into_iter().map(move |selection| {
 5241            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 5242
 5243            let mut enclosing = None;
 5244            while let Some(pair_state) = regions.get(i) {
 5245                if pair_state.range.end.to_offset(buffer) < range.start {
 5246                    regions = &regions[i + 1..];
 5247                    i = 0;
 5248                } else if pair_state.range.start.to_offset(buffer) > range.end {
 5249                    break;
 5250                } else {
 5251                    if pair_state.selection_id == selection.id {
 5252                        enclosing = Some(pair_state);
 5253                    }
 5254                    i += 1;
 5255                }
 5256            }
 5257
 5258            (selection, enclosing)
 5259        })
 5260    }
 5261
 5262    /// Remove any autoclose regions that no longer contain their selection or have invalid anchors in ranges.
 5263    fn invalidate_autoclose_regions(
 5264        &mut self,
 5265        mut selections: &[Selection<Anchor>],
 5266        buffer: &MultiBufferSnapshot,
 5267    ) {
 5268        self.autoclose_regions.retain(|state| {
 5269            if !state.range.start.is_valid(buffer) || !state.range.end.is_valid(buffer) {
 5270                return false;
 5271            }
 5272
 5273            let mut i = 0;
 5274            while let Some(selection) = selections.get(i) {
 5275                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 5276                    selections = &selections[1..];
 5277                    continue;
 5278                }
 5279                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 5280                    break;
 5281                }
 5282                if selection.id == state.selection_id {
 5283                    return true;
 5284                } else {
 5285                    i += 1;
 5286                }
 5287            }
 5288            false
 5289        });
 5290    }
 5291
 5292    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 5293        let offset = position.to_offset(buffer);
 5294        let (word_range, kind) =
 5295            buffer.surrounding_word(offset, Some(CharScopeContext::Completion));
 5296        if offset > word_range.start && kind == Some(CharKind::Word) {
 5297            Some(
 5298                buffer
 5299                    .text_for_range(word_range.start..offset)
 5300                    .collect::<String>(),
 5301            )
 5302        } else {
 5303            None
 5304        }
 5305    }
 5306
 5307    pub fn visible_excerpts(
 5308        &self,
 5309        cx: &mut Context<Editor>,
 5310    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 5311        let Some(project) = self.project() else {
 5312            return HashMap::default();
 5313        };
 5314        let project = project.read(cx);
 5315        let multi_buffer = self.buffer().read(cx);
 5316        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 5317        let multi_buffer_visible_start = self
 5318            .scroll_manager
 5319            .anchor()
 5320            .anchor
 5321            .to_point(&multi_buffer_snapshot);
 5322        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 5323            multi_buffer_visible_start
 5324                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 5325            Bias::Left,
 5326        );
 5327        multi_buffer_snapshot
 5328            .range_to_buffer_ranges(multi_buffer_visible_start..multi_buffer_visible_end)
 5329            .into_iter()
 5330            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 5331            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 5332                let buffer_file = project::File::from_dyn(buffer.file())?;
 5333                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 5334                let worktree_entry = buffer_worktree
 5335                    .read(cx)
 5336                    .entry_for_id(buffer_file.project_entry_id()?)?;
 5337                if worktree_entry.is_ignored {
 5338                    None
 5339                } else {
 5340                    Some((
 5341                        excerpt_id,
 5342                        (
 5343                            multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5344                            buffer.version().clone(),
 5345                            excerpt_visible_range.start.0..excerpt_visible_range.end.0,
 5346                        ),
 5347                    ))
 5348                }
 5349            })
 5350            .collect()
 5351    }
 5352
 5353    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 5354        TextLayoutDetails {
 5355            text_system: window.text_system().clone(),
 5356            editor_style: self.style.clone().unwrap(),
 5357            rem_size: window.rem_size(),
 5358            scroll_anchor: self.scroll_manager.anchor(),
 5359            visible_rows: self.visible_line_count(),
 5360            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 5361        }
 5362    }
 5363
 5364    fn trigger_on_type_formatting(
 5365        &self,
 5366        input: String,
 5367        window: &mut Window,
 5368        cx: &mut Context<Self>,
 5369    ) -> Option<Task<Result<()>>> {
 5370        if input.len() != 1 {
 5371            return None;
 5372        }
 5373
 5374        let project = self.project()?;
 5375        let position = self.selections.newest_anchor().head();
 5376        let (buffer, buffer_position) = self
 5377            .buffer
 5378            .read(cx)
 5379            .text_anchor_for_position(position, cx)?;
 5380
 5381        let settings = language_settings::language_settings(
 5382            buffer
 5383                .read(cx)
 5384                .language_at(buffer_position)
 5385                .map(|l| l.name()),
 5386            buffer.read(cx).file(),
 5387            cx,
 5388        );
 5389        if !settings.use_on_type_format {
 5390            return None;
 5391        }
 5392
 5393        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5394        // hence we do LSP request & edit on host side only — add formats to host's history.
 5395        let push_to_lsp_host_history = true;
 5396        // If this is not the host, append its history with new edits.
 5397        let push_to_client_history = project.read(cx).is_via_collab();
 5398
 5399        let on_type_formatting = project.update(cx, |project, cx| {
 5400            project.on_type_format(
 5401                buffer.clone(),
 5402                buffer_position,
 5403                input,
 5404                push_to_lsp_host_history,
 5405                cx,
 5406            )
 5407        });
 5408        Some(cx.spawn_in(window, async move |editor, cx| {
 5409            if let Some(transaction) = on_type_formatting.await? {
 5410                if push_to_client_history {
 5411                    buffer
 5412                        .update(cx, |buffer, _| {
 5413                            buffer.push_transaction(transaction, Instant::now());
 5414                            buffer.finalize_last_transaction();
 5415                        })
 5416                        .ok();
 5417                }
 5418                editor.update(cx, |editor, cx| {
 5419                    editor.refresh_document_highlights(cx);
 5420                })?;
 5421            }
 5422            Ok(())
 5423        }))
 5424    }
 5425
 5426    pub fn show_word_completions(
 5427        &mut self,
 5428        _: &ShowWordCompletions,
 5429        window: &mut Window,
 5430        cx: &mut Context<Self>,
 5431    ) {
 5432        self.open_or_update_completions_menu(
 5433            Some(CompletionsMenuSource::Words {
 5434                ignore_threshold: true,
 5435            }),
 5436            None,
 5437            false,
 5438            window,
 5439            cx,
 5440        );
 5441    }
 5442
 5443    pub fn show_completions(
 5444        &mut self,
 5445        _: &ShowCompletions,
 5446        window: &mut Window,
 5447        cx: &mut Context<Self>,
 5448    ) {
 5449        self.open_or_update_completions_menu(None, None, false, window, cx);
 5450    }
 5451
 5452    fn open_or_update_completions_menu(
 5453        &mut self,
 5454        requested_source: Option<CompletionsMenuSource>,
 5455        trigger: Option<String>,
 5456        trigger_in_words: bool,
 5457        window: &mut Window,
 5458        cx: &mut Context<Self>,
 5459    ) {
 5460        if self.pending_rename.is_some() {
 5461            return;
 5462        }
 5463
 5464        let completions_source = self
 5465            .context_menu
 5466            .borrow()
 5467            .as_ref()
 5468            .and_then(|menu| match menu {
 5469                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 5470                CodeContextMenu::CodeActions(_) => None,
 5471            });
 5472
 5473        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5474
 5475        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5476        // inserted and selected. To handle that case, the start of the selection is used so that
 5477        // the menu starts with all choices.
 5478        let position = self
 5479            .selections
 5480            .newest_anchor()
 5481            .start
 5482            .bias_right(&multibuffer_snapshot);
 5483        if position.diff_base_anchor.is_some() {
 5484            return;
 5485        }
 5486        let buffer_position = multibuffer_snapshot.anchor_before(position);
 5487        let Some(buffer) = buffer_position
 5488            .buffer_id
 5489            .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
 5490        else {
 5491            return;
 5492        };
 5493        let buffer_snapshot = buffer.read(cx).snapshot();
 5494
 5495        let query: Option<Arc<String>> =
 5496            Self::completion_query(&multibuffer_snapshot, buffer_position)
 5497                .map(|query| query.into());
 5498
 5499        drop(multibuffer_snapshot);
 5500
 5501        // Hide the current completions menu when query is empty. Without this, cached
 5502        // completions from before the trigger char may be reused (#32774).
 5503        if query.is_none() {
 5504            let menu_is_open = matches!(
 5505                self.context_menu.borrow().as_ref(),
 5506                Some(CodeContextMenu::Completions(_))
 5507            );
 5508            if menu_is_open {
 5509                self.hide_context_menu(window, cx);
 5510            }
 5511        }
 5512
 5513        let mut ignore_word_threshold = false;
 5514        let provider = match requested_source {
 5515            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5516            Some(CompletionsMenuSource::Words { ignore_threshold }) => {
 5517                ignore_word_threshold = ignore_threshold;
 5518                None
 5519            }
 5520            Some(CompletionsMenuSource::SnippetChoices)
 5521            | Some(CompletionsMenuSource::SnippetsOnly) => {
 5522                log::error!("bug: SnippetChoices requested_source is not handled");
 5523                None
 5524            }
 5525        };
 5526
 5527        let sort_completions = provider
 5528            .as_ref()
 5529            .is_some_and(|provider| provider.sort_completions());
 5530
 5531        let filter_completions = provider
 5532            .as_ref()
 5533            .is_none_or(|provider| provider.filter_completions());
 5534
 5535        let was_snippets_only = matches!(
 5536            completions_source,
 5537            Some(CompletionsMenuSource::SnippetsOnly)
 5538        );
 5539
 5540        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5541            if filter_completions {
 5542                menu.filter(
 5543                    query.clone().unwrap_or_default(),
 5544                    buffer_position.text_anchor,
 5545                    &buffer,
 5546                    provider.clone(),
 5547                    window,
 5548                    cx,
 5549                );
 5550            }
 5551            // When `is_incomplete` is false, no need to re-query completions when the current query
 5552            // is a suffix of the initial query.
 5553            let was_complete = !menu.is_incomplete;
 5554            if was_complete && !was_snippets_only {
 5555                // If the new query is a suffix of the old query (typing more characters) and
 5556                // the previous result was complete, the existing completions can be filtered.
 5557                //
 5558                // Note that snippet completions are always complete.
 5559                let query_matches = match (&menu.initial_query, &query) {
 5560                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5561                    (None, _) => true,
 5562                    _ => false,
 5563                };
 5564                if query_matches {
 5565                    let position_matches = if menu.initial_position == position {
 5566                        true
 5567                    } else {
 5568                        let snapshot = self.buffer.read(cx).read(cx);
 5569                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5570                    };
 5571                    if position_matches {
 5572                        return;
 5573                    }
 5574                }
 5575            }
 5576        };
 5577
 5578        let Anchor {
 5579            excerpt_id: buffer_excerpt_id,
 5580            text_anchor: buffer_position,
 5581            ..
 5582        } = buffer_position;
 5583
 5584        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5585            buffer_snapshot.surrounding_word(buffer_position, None)
 5586        {
 5587            let word_to_exclude = buffer_snapshot
 5588                .text_for_range(word_range.clone())
 5589                .collect::<String>();
 5590            (
 5591                buffer_snapshot.anchor_before(word_range.start)
 5592                    ..buffer_snapshot.anchor_after(buffer_position),
 5593                Some(word_to_exclude),
 5594            )
 5595        } else {
 5596            (buffer_position..buffer_position, None)
 5597        };
 5598
 5599        let language = buffer_snapshot
 5600            .language_at(buffer_position)
 5601            .map(|language| language.name());
 5602
 5603        let completion_settings = language_settings(language.clone(), buffer_snapshot.file(), cx)
 5604            .completions
 5605            .clone();
 5606
 5607        let show_completion_documentation = buffer_snapshot
 5608            .settings_at(buffer_position, cx)
 5609            .show_completion_documentation;
 5610
 5611        // The document can be large, so stay in reasonable bounds when searching for words,
 5612        // otherwise completion pop-up might be slow to appear.
 5613        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5614        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5615        let min_word_search = buffer_snapshot.clip_point(
 5616            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5617            Bias::Left,
 5618        );
 5619        let max_word_search = buffer_snapshot.clip_point(
 5620            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5621            Bias::Right,
 5622        );
 5623        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5624            ..buffer_snapshot.point_to_offset(max_word_search);
 5625
 5626        let skip_digits = query
 5627            .as_ref()
 5628            .is_none_or(|query| !query.chars().any(|c| c.is_digit(10)));
 5629
 5630        let load_provider_completions = provider.as_ref().is_some_and(|provider| {
 5631            trigger.as_ref().is_none_or(|trigger| {
 5632                provider.is_completion_trigger(
 5633                    &buffer,
 5634                    position.text_anchor,
 5635                    trigger,
 5636                    trigger_in_words,
 5637                    completions_source.is_some(),
 5638                    cx,
 5639                )
 5640            })
 5641        });
 5642
 5643        let provider_responses = if let Some(provider) = &provider
 5644            && load_provider_completions
 5645        {
 5646            let trigger_character =
 5647                trigger.filter(|trigger| buffer.read(cx).completion_triggers().contains(trigger));
 5648            let completion_context = CompletionContext {
 5649                trigger_kind: match &trigger_character {
 5650                    Some(_) => CompletionTriggerKind::TRIGGER_CHARACTER,
 5651                    None => CompletionTriggerKind::INVOKED,
 5652                },
 5653                trigger_character,
 5654            };
 5655
 5656            provider.completions(
 5657                buffer_excerpt_id,
 5658                &buffer,
 5659                buffer_position,
 5660                completion_context,
 5661                window,
 5662                cx,
 5663            )
 5664        } else {
 5665            Task::ready(Ok(Vec::new()))
 5666        };
 5667
 5668        let load_word_completions = if !self.word_completions_enabled {
 5669            false
 5670        } else if requested_source
 5671            == Some(CompletionsMenuSource::Words {
 5672                ignore_threshold: true,
 5673            })
 5674        {
 5675            true
 5676        } else {
 5677            load_provider_completions
 5678                && completion_settings.words != WordsCompletionMode::Disabled
 5679                && (ignore_word_threshold || {
 5680                    let words_min_length = completion_settings.words_min_length;
 5681                    // check whether word has at least `words_min_length` characters
 5682                    let query_chars = query.iter().flat_map(|q| q.chars());
 5683                    query_chars.take(words_min_length).count() == words_min_length
 5684                })
 5685        };
 5686
 5687        let mut words = if load_word_completions {
 5688            cx.background_spawn({
 5689                let buffer_snapshot = buffer_snapshot.clone();
 5690                async move {
 5691                    buffer_snapshot.words_in_range(WordsQuery {
 5692                        fuzzy_contents: None,
 5693                        range: word_search_range,
 5694                        skip_digits,
 5695                    })
 5696                }
 5697            })
 5698        } else {
 5699            Task::ready(BTreeMap::default())
 5700        };
 5701
 5702        let snippets = if let Some(provider) = &provider
 5703            && provider.show_snippets()
 5704            && let Some(project) = self.project()
 5705        {
 5706            let char_classifier = buffer_snapshot
 5707                .char_classifier_at(buffer_position)
 5708                .scope_context(Some(CharScopeContext::Completion));
 5709            project.update(cx, |project, cx| {
 5710                snippet_completions(project, &buffer, buffer_position, char_classifier, cx)
 5711            })
 5712        } else {
 5713            Task::ready(Ok(CompletionResponse {
 5714                completions: Vec::new(),
 5715                display_options: Default::default(),
 5716                is_incomplete: false,
 5717            }))
 5718        };
 5719
 5720        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5721
 5722        let id = post_inc(&mut self.next_completion_id);
 5723        let task = cx.spawn_in(window, async move |editor, cx| {
 5724            let Ok(()) = editor.update(cx, |this, _| {
 5725                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5726            }) else {
 5727                return;
 5728            };
 5729
 5730            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5731            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5732            let mut completions = Vec::new();
 5733            let mut is_incomplete = false;
 5734            let mut display_options: Option<CompletionDisplayOptions> = None;
 5735            if let Some(provider_responses) = provider_responses.await.log_err()
 5736                && !provider_responses.is_empty()
 5737            {
 5738                for response in provider_responses {
 5739                    completions.extend(response.completions);
 5740                    is_incomplete = is_incomplete || response.is_incomplete;
 5741                    match display_options.as_mut() {
 5742                        None => {
 5743                            display_options = Some(response.display_options);
 5744                        }
 5745                        Some(options) => options.merge(&response.display_options),
 5746                    }
 5747                }
 5748                if completion_settings.words == WordsCompletionMode::Fallback {
 5749                    words = Task::ready(BTreeMap::default());
 5750                }
 5751            }
 5752            let display_options = display_options.unwrap_or_default();
 5753
 5754            let mut words = words.await;
 5755            if let Some(word_to_exclude) = &word_to_exclude {
 5756                words.remove(word_to_exclude);
 5757            }
 5758            for lsp_completion in &completions {
 5759                words.remove(&lsp_completion.new_text);
 5760            }
 5761            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5762                replace_range: word_replace_range.clone(),
 5763                new_text: word.clone(),
 5764                label: CodeLabel::plain(word, None),
 5765                match_start: None,
 5766                snippet_deduplication_key: None,
 5767                icon_path: None,
 5768                documentation: None,
 5769                source: CompletionSource::BufferWord {
 5770                    word_range,
 5771                    resolved: false,
 5772                },
 5773                insert_text_mode: Some(InsertTextMode::AS_IS),
 5774                confirm: None,
 5775            }));
 5776
 5777            completions.extend(
 5778                snippets
 5779                    .await
 5780                    .into_iter()
 5781                    .flat_map(|response| response.completions),
 5782            );
 5783
 5784            let menu = if completions.is_empty() {
 5785                None
 5786            } else {
 5787                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5788                    let languages = editor
 5789                        .workspace
 5790                        .as_ref()
 5791                        .and_then(|(workspace, _)| workspace.upgrade())
 5792                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5793                    let menu = CompletionsMenu::new(
 5794                        id,
 5795                        requested_source.unwrap_or(if load_provider_completions {
 5796                            CompletionsMenuSource::Normal
 5797                        } else {
 5798                            CompletionsMenuSource::SnippetsOnly
 5799                        }),
 5800                        sort_completions,
 5801                        show_completion_documentation,
 5802                        position,
 5803                        query.clone(),
 5804                        is_incomplete,
 5805                        buffer.clone(),
 5806                        completions.into(),
 5807                        display_options,
 5808                        snippet_sort_order,
 5809                        languages,
 5810                        language,
 5811                        cx,
 5812                    );
 5813
 5814                    let query = if filter_completions { query } else { None };
 5815                    let matches_task = menu.do_async_filtering(
 5816                        query.unwrap_or_default(),
 5817                        buffer_position,
 5818                        &buffer,
 5819                        cx,
 5820                    );
 5821                    (menu, matches_task)
 5822                }) else {
 5823                    return;
 5824                };
 5825
 5826                let matches = matches_task.await;
 5827
 5828                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5829                    // Newer menu already set, so exit.
 5830                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5831                        editor.context_menu.borrow().as_ref()
 5832                        && prev_menu.id > id
 5833                    {
 5834                        return;
 5835                    };
 5836
 5837                    // Only valid to take prev_menu because either the new menu is immediately set
 5838                    // below, or the menu is hidden.
 5839                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5840                        editor.context_menu.borrow_mut().take()
 5841                    {
 5842                        let position_matches =
 5843                            if prev_menu.initial_position == menu.initial_position {
 5844                                true
 5845                            } else {
 5846                                let snapshot = editor.buffer.read(cx).read(cx);
 5847                                prev_menu.initial_position.to_offset(&snapshot)
 5848                                    == menu.initial_position.to_offset(&snapshot)
 5849                            };
 5850                        if position_matches {
 5851                            // Preserve markdown cache before `set_filter_results` because it will
 5852                            // try to populate the documentation cache.
 5853                            menu.preserve_markdown_cache(prev_menu);
 5854                        }
 5855                    };
 5856
 5857                    menu.set_filter_results(matches, provider, window, cx);
 5858                }) else {
 5859                    return;
 5860                };
 5861
 5862                menu.visible().then_some(menu)
 5863            };
 5864
 5865            editor
 5866                .update_in(cx, |editor, window, cx| {
 5867                    if editor.focus_handle.is_focused(window)
 5868                        && let Some(menu) = menu
 5869                    {
 5870                        *editor.context_menu.borrow_mut() =
 5871                            Some(CodeContextMenu::Completions(menu));
 5872
 5873                        crate::hover_popover::hide_hover(editor, cx);
 5874                        if editor.show_edit_predictions_in_menu() {
 5875                            editor.update_visible_edit_prediction(window, cx);
 5876                        } else {
 5877                            editor.discard_edit_prediction(false, cx);
 5878                        }
 5879
 5880                        cx.notify();
 5881                        return;
 5882                    }
 5883
 5884                    if editor.completion_tasks.len() <= 1 {
 5885                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 5886                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5887                        // If it was already hidden and we don't show edit predictions in the menu,
 5888                        // we should also show the edit prediction when available.
 5889                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5890                            editor.update_visible_edit_prediction(window, cx);
 5891                        }
 5892                    }
 5893                })
 5894                .ok();
 5895        });
 5896
 5897        self.completion_tasks.push((id, task));
 5898    }
 5899
 5900    #[cfg(feature = "test-support")]
 5901    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5902        let menu = self.context_menu.borrow();
 5903        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5904            let completions = menu.completions.borrow();
 5905            Some(completions.to_vec())
 5906        } else {
 5907            None
 5908        }
 5909    }
 5910
 5911    pub fn with_completions_menu_matching_id<R>(
 5912        &self,
 5913        id: CompletionId,
 5914        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 5915    ) -> R {
 5916        let mut context_menu = self.context_menu.borrow_mut();
 5917        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 5918            return f(None);
 5919        };
 5920        if completions_menu.id != id {
 5921            return f(None);
 5922        }
 5923        f(Some(completions_menu))
 5924    }
 5925
 5926    pub fn confirm_completion(
 5927        &mut self,
 5928        action: &ConfirmCompletion,
 5929        window: &mut Window,
 5930        cx: &mut Context<Self>,
 5931    ) -> Option<Task<Result<()>>> {
 5932        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5933        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5934    }
 5935
 5936    pub fn confirm_completion_insert(
 5937        &mut self,
 5938        _: &ConfirmCompletionInsert,
 5939        window: &mut Window,
 5940        cx: &mut Context<Self>,
 5941    ) -> Option<Task<Result<()>>> {
 5942        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5943        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5944    }
 5945
 5946    pub fn confirm_completion_replace(
 5947        &mut self,
 5948        _: &ConfirmCompletionReplace,
 5949        window: &mut Window,
 5950        cx: &mut Context<Self>,
 5951    ) -> Option<Task<Result<()>>> {
 5952        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5953        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5954    }
 5955
 5956    pub fn compose_completion(
 5957        &mut self,
 5958        action: &ComposeCompletion,
 5959        window: &mut Window,
 5960        cx: &mut Context<Self>,
 5961    ) -> Option<Task<Result<()>>> {
 5962        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5963        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5964    }
 5965
 5966    fn do_completion(
 5967        &mut self,
 5968        item_ix: Option<usize>,
 5969        intent: CompletionIntent,
 5970        window: &mut Window,
 5971        cx: &mut Context<Editor>,
 5972    ) -> Option<Task<Result<()>>> {
 5973        use language::ToOffset as _;
 5974
 5975        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5976        else {
 5977            return None;
 5978        };
 5979
 5980        let candidate_id = {
 5981            let entries = completions_menu.entries.borrow();
 5982            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5983            if self.show_edit_predictions_in_menu() {
 5984                self.discard_edit_prediction(true, cx);
 5985            }
 5986            mat.candidate_id
 5987        };
 5988
 5989        let completion = completions_menu
 5990            .completions
 5991            .borrow()
 5992            .get(candidate_id)?
 5993            .clone();
 5994        cx.stop_propagation();
 5995
 5996        let buffer_handle = completions_menu.buffer.clone();
 5997
 5998        let CompletionEdit {
 5999            new_text,
 6000            snippet,
 6001            replace_range,
 6002        } = process_completion_for_edit(
 6003            &completion,
 6004            intent,
 6005            &buffer_handle,
 6006            &completions_menu.initial_position.text_anchor,
 6007            cx,
 6008        );
 6009
 6010        let buffer = buffer_handle.read(cx);
 6011        let snapshot = self.buffer.read(cx).snapshot(cx);
 6012        let newest_anchor = self.selections.newest_anchor();
 6013        let replace_range_multibuffer = {
 6014            let mut excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 6015            excerpt.map_range_from_buffer(replace_range.clone())
 6016        };
 6017        if snapshot.buffer_id_for_anchor(newest_anchor.head()) != Some(buffer.remote_id()) {
 6018            return None;
 6019        }
 6020
 6021        let old_text = buffer
 6022            .text_for_range(replace_range.clone())
 6023            .collect::<String>();
 6024        let lookbehind = newest_anchor
 6025            .start
 6026            .text_anchor
 6027            .to_offset(buffer)
 6028            .saturating_sub(replace_range.start.0);
 6029        let lookahead = replace_range
 6030            .end
 6031            .0
 6032            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 6033        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 6034        let suffix = &old_text[lookbehind.min(old_text.len())..];
 6035
 6036        let selections = self
 6037            .selections
 6038            .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 6039        let mut ranges = Vec::new();
 6040        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 6041
 6042        for selection in &selections {
 6043            let range = if selection.id == newest_anchor.id {
 6044                replace_range_multibuffer.clone()
 6045            } else {
 6046                let mut range = selection.range();
 6047
 6048                // if prefix is present, don't duplicate it
 6049                if snapshot.contains_str_at(range.start.saturating_sub_usize(lookbehind), prefix) {
 6050                    range.start = range.start.saturating_sub_usize(lookbehind);
 6051
 6052                    // if suffix is also present, mimic the newest cursor and replace it
 6053                    if selection.id != newest_anchor.id
 6054                        && snapshot.contains_str_at(range.end, suffix)
 6055                    {
 6056                        range.end += lookahead;
 6057                    }
 6058                }
 6059                range
 6060            };
 6061
 6062            ranges.push(range.clone());
 6063
 6064            if !self.linked_edit_ranges.is_empty() {
 6065                let start_anchor = snapshot.anchor_before(range.start);
 6066                let end_anchor = snapshot.anchor_after(range.end);
 6067                if let Some(ranges) = self
 6068                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 6069                {
 6070                    for (buffer, edits) in ranges {
 6071                        linked_edits
 6072                            .entry(buffer.clone())
 6073                            .or_default()
 6074                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 6075                    }
 6076                }
 6077            }
 6078        }
 6079
 6080        let common_prefix_len = old_text
 6081            .chars()
 6082            .zip(new_text.chars())
 6083            .take_while(|(a, b)| a == b)
 6084            .map(|(a, _)| a.len_utf8())
 6085            .sum::<usize>();
 6086
 6087        cx.emit(EditorEvent::InputHandled {
 6088            utf16_range_to_replace: None,
 6089            text: new_text[common_prefix_len..].into(),
 6090        });
 6091
 6092        self.transact(window, cx, |editor, window, cx| {
 6093            if let Some(mut snippet) = snippet {
 6094                snippet.text = new_text.to_string();
 6095                editor
 6096                    .insert_snippet(&ranges, snippet, window, cx)
 6097                    .log_err();
 6098            } else {
 6099                editor.buffer.update(cx, |multi_buffer, cx| {
 6100                    let auto_indent = match completion.insert_text_mode {
 6101                        Some(InsertTextMode::AS_IS) => None,
 6102                        _ => editor.autoindent_mode.clone(),
 6103                    };
 6104                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 6105                    multi_buffer.edit(edits, auto_indent, cx);
 6106                });
 6107            }
 6108            for (buffer, edits) in linked_edits {
 6109                buffer.update(cx, |buffer, cx| {
 6110                    let snapshot = buffer.snapshot();
 6111                    let edits = edits
 6112                        .into_iter()
 6113                        .map(|(range, text)| {
 6114                            use text::ToPoint as TP;
 6115                            let end_point = TP::to_point(&range.end, &snapshot);
 6116                            let start_point = TP::to_point(&range.start, &snapshot);
 6117                            (start_point..end_point, text)
 6118                        })
 6119                        .sorted_by_key(|(range, _)| range.start);
 6120                    buffer.edit(edits, None, cx);
 6121                })
 6122            }
 6123
 6124            editor.refresh_edit_prediction(true, false, window, cx);
 6125        });
 6126        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors_arc(), &snapshot);
 6127
 6128        let show_new_completions_on_confirm = completion
 6129            .confirm
 6130            .as_ref()
 6131            .is_some_and(|confirm| confirm(intent, window, cx));
 6132        if show_new_completions_on_confirm {
 6133            self.open_or_update_completions_menu(None, None, false, window, cx);
 6134        }
 6135
 6136        let provider = self.completion_provider.as_ref()?;
 6137        drop(completion);
 6138        let apply_edits = provider.apply_additional_edits_for_completion(
 6139            buffer_handle,
 6140            completions_menu.completions.clone(),
 6141            candidate_id,
 6142            true,
 6143            cx,
 6144        );
 6145
 6146        let editor_settings = EditorSettings::get_global(cx);
 6147        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 6148            // After the code completion is finished, users often want to know what signatures are needed.
 6149            // so we should automatically call signature_help
 6150            self.show_signature_help(&ShowSignatureHelp, window, cx);
 6151        }
 6152
 6153        Some(cx.foreground_executor().spawn(async move {
 6154            apply_edits.await?;
 6155            Ok(())
 6156        }))
 6157    }
 6158
 6159    pub fn toggle_code_actions(
 6160        &mut self,
 6161        action: &ToggleCodeActions,
 6162        window: &mut Window,
 6163        cx: &mut Context<Self>,
 6164    ) {
 6165        let quick_launch = action.quick_launch;
 6166        let mut context_menu = self.context_menu.borrow_mut();
 6167        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 6168            if code_actions.deployed_from == action.deployed_from {
 6169                // Toggle if we're selecting the same one
 6170                *context_menu = None;
 6171                cx.notify();
 6172                return;
 6173            } else {
 6174                // Otherwise, clear it and start a new one
 6175                *context_menu = None;
 6176                cx.notify();
 6177            }
 6178        }
 6179        drop(context_menu);
 6180        let snapshot = self.snapshot(window, cx);
 6181        let deployed_from = action.deployed_from.clone();
 6182        let action = action.clone();
 6183        self.completion_tasks.clear();
 6184        self.discard_edit_prediction(false, cx);
 6185
 6186        let multibuffer_point = match &action.deployed_from {
 6187            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 6188                DisplayPoint::new(*row, 0).to_point(&snapshot)
 6189            }
 6190            _ => self
 6191                .selections
 6192                .newest::<Point>(&snapshot.display_snapshot)
 6193                .head(),
 6194        };
 6195        let Some((buffer, buffer_row)) = snapshot
 6196            .buffer_snapshot()
 6197            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 6198            .and_then(|(buffer_snapshot, range)| {
 6199                self.buffer()
 6200                    .read(cx)
 6201                    .buffer(buffer_snapshot.remote_id())
 6202                    .map(|buffer| (buffer, range.start.row))
 6203            })
 6204        else {
 6205            return;
 6206        };
 6207        let buffer_id = buffer.read(cx).remote_id();
 6208        let tasks = self
 6209            .tasks
 6210            .get(&(buffer_id, buffer_row))
 6211            .map(|t| Arc::new(t.to_owned()));
 6212
 6213        if !self.focus_handle.is_focused(window) {
 6214            return;
 6215        }
 6216        let project = self.project.clone();
 6217
 6218        let code_actions_task = match deployed_from {
 6219            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 6220            _ => self.code_actions(buffer_row, window, cx),
 6221        };
 6222
 6223        let runnable_task = match deployed_from {
 6224            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 6225            _ => {
 6226                let mut task_context_task = Task::ready(None);
 6227                if let Some(tasks) = &tasks
 6228                    && let Some(project) = project
 6229                {
 6230                    task_context_task =
 6231                        Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx);
 6232                }
 6233
 6234                cx.spawn_in(window, {
 6235                    let buffer = buffer.clone();
 6236                    async move |editor, cx| {
 6237                        let task_context = task_context_task.await;
 6238
 6239                        let resolved_tasks =
 6240                            tasks
 6241                                .zip(task_context.clone())
 6242                                .map(|(tasks, task_context)| ResolvedTasks {
 6243                                    templates: tasks.resolve(&task_context).collect(),
 6244                                    position: snapshot.buffer_snapshot().anchor_before(Point::new(
 6245                                        multibuffer_point.row,
 6246                                        tasks.column,
 6247                                    )),
 6248                                });
 6249                        let debug_scenarios = editor
 6250                            .update(cx, |editor, cx| {
 6251                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 6252                            })?
 6253                            .await;
 6254                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 6255                    }
 6256                })
 6257            }
 6258        };
 6259
 6260        cx.spawn_in(window, async move |editor, cx| {
 6261            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 6262            let code_actions = code_actions_task.await;
 6263            let spawn_straight_away = quick_launch
 6264                && resolved_tasks
 6265                    .as_ref()
 6266                    .is_some_and(|tasks| tasks.templates.len() == 1)
 6267                && code_actions
 6268                    .as_ref()
 6269                    .is_none_or(|actions| actions.is_empty())
 6270                && debug_scenarios.is_empty();
 6271
 6272            editor.update_in(cx, |editor, window, cx| {
 6273                crate::hover_popover::hide_hover(editor, cx);
 6274                let actions = CodeActionContents::new(
 6275                    resolved_tasks,
 6276                    code_actions,
 6277                    debug_scenarios,
 6278                    task_context.unwrap_or_default(),
 6279                );
 6280
 6281                // Don't show the menu if there are no actions available
 6282                if actions.is_empty() {
 6283                    cx.notify();
 6284                    return Task::ready(Ok(()));
 6285                }
 6286
 6287                *editor.context_menu.borrow_mut() =
 6288                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 6289                        buffer,
 6290                        actions,
 6291                        selected_item: Default::default(),
 6292                        scroll_handle: UniformListScrollHandle::default(),
 6293                        deployed_from,
 6294                    }));
 6295                cx.notify();
 6296                if spawn_straight_away
 6297                    && let Some(task) = editor.confirm_code_action(
 6298                        &ConfirmCodeAction { item_ix: Some(0) },
 6299                        window,
 6300                        cx,
 6301                    )
 6302                {
 6303                    return task;
 6304                }
 6305
 6306                Task::ready(Ok(()))
 6307            })
 6308        })
 6309        .detach_and_log_err(cx);
 6310    }
 6311
 6312    fn debug_scenarios(
 6313        &mut self,
 6314        resolved_tasks: &Option<ResolvedTasks>,
 6315        buffer: &Entity<Buffer>,
 6316        cx: &mut App,
 6317    ) -> Task<Vec<task::DebugScenario>> {
 6318        maybe!({
 6319            let project = self.project()?;
 6320            let dap_store = project.read(cx).dap_store();
 6321            let mut scenarios = vec![];
 6322            let resolved_tasks = resolved_tasks.as_ref()?;
 6323            let buffer = buffer.read(cx);
 6324            let language = buffer.language()?;
 6325            let file = buffer.file();
 6326            let debug_adapter = language_settings(language.name().into(), file, cx)
 6327                .debuggers
 6328                .first()
 6329                .map(SharedString::from)
 6330                .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 6331
 6332            dap_store.update(cx, |dap_store, cx| {
 6333                for (_, task) in &resolved_tasks.templates {
 6334                    let maybe_scenario = dap_store.debug_scenario_for_build_task(
 6335                        task.original_task().clone(),
 6336                        debug_adapter.clone().into(),
 6337                        task.display_label().to_owned().into(),
 6338                        cx,
 6339                    );
 6340                    scenarios.push(maybe_scenario);
 6341                }
 6342            });
 6343            Some(cx.background_spawn(async move {
 6344                futures::future::join_all(scenarios)
 6345                    .await
 6346                    .into_iter()
 6347                    .flatten()
 6348                    .collect::<Vec<_>>()
 6349            }))
 6350        })
 6351        .unwrap_or_else(|| Task::ready(vec![]))
 6352    }
 6353
 6354    fn code_actions(
 6355        &mut self,
 6356        buffer_row: u32,
 6357        window: &mut Window,
 6358        cx: &mut Context<Self>,
 6359    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 6360        let mut task = self.code_actions_task.take();
 6361        cx.spawn_in(window, async move |editor, cx| {
 6362            while let Some(prev_task) = task {
 6363                prev_task.await.log_err();
 6364                task = editor
 6365                    .update(cx, |this, _| this.code_actions_task.take())
 6366                    .ok()?;
 6367            }
 6368
 6369            editor
 6370                .update(cx, |editor, cx| {
 6371                    editor
 6372                        .available_code_actions
 6373                        .clone()
 6374                        .and_then(|(location, code_actions)| {
 6375                            let snapshot = location.buffer.read(cx).snapshot();
 6376                            let point_range = location.range.to_point(&snapshot);
 6377                            let point_range = point_range.start.row..=point_range.end.row;
 6378                            if point_range.contains(&buffer_row) {
 6379                                Some(code_actions)
 6380                            } else {
 6381                                None
 6382                            }
 6383                        })
 6384                })
 6385                .ok()
 6386                .flatten()
 6387        })
 6388    }
 6389
 6390    pub fn confirm_code_action(
 6391        &mut self,
 6392        action: &ConfirmCodeAction,
 6393        window: &mut Window,
 6394        cx: &mut Context<Self>,
 6395    ) -> Option<Task<Result<()>>> {
 6396        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6397
 6398        let actions_menu =
 6399            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 6400                menu
 6401            } else {
 6402                return None;
 6403            };
 6404
 6405        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 6406        let action = actions_menu.actions.get(action_ix)?;
 6407        let title = action.label();
 6408        let buffer = actions_menu.buffer;
 6409        let workspace = self.workspace()?;
 6410
 6411        match action {
 6412            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 6413                workspace.update(cx, |workspace, cx| {
 6414                    workspace.schedule_resolved_task(
 6415                        task_source_kind,
 6416                        resolved_task,
 6417                        false,
 6418                        window,
 6419                        cx,
 6420                    );
 6421
 6422                    Some(Task::ready(Ok(())))
 6423                })
 6424            }
 6425            CodeActionsItem::CodeAction {
 6426                excerpt_id,
 6427                action,
 6428                provider,
 6429            } => {
 6430                let apply_code_action =
 6431                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 6432                let workspace = workspace.downgrade();
 6433                Some(cx.spawn_in(window, async move |editor, cx| {
 6434                    let project_transaction = apply_code_action.await?;
 6435                    Self::open_project_transaction(
 6436                        &editor,
 6437                        workspace,
 6438                        project_transaction,
 6439                        title,
 6440                        cx,
 6441                    )
 6442                    .await
 6443                }))
 6444            }
 6445            CodeActionsItem::DebugScenario(scenario) => {
 6446                let context = actions_menu.actions.context;
 6447
 6448                workspace.update(cx, |workspace, cx| {
 6449                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 6450                    workspace.start_debug_session(
 6451                        scenario,
 6452                        context,
 6453                        Some(buffer),
 6454                        None,
 6455                        window,
 6456                        cx,
 6457                    );
 6458                });
 6459                Some(Task::ready(Ok(())))
 6460            }
 6461        }
 6462    }
 6463
 6464    pub async fn open_project_transaction(
 6465        editor: &WeakEntity<Editor>,
 6466        workspace: WeakEntity<Workspace>,
 6467        transaction: ProjectTransaction,
 6468        title: String,
 6469        cx: &mut AsyncWindowContext,
 6470    ) -> Result<()> {
 6471        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 6472        cx.update(|_, cx| {
 6473            entries.sort_unstable_by_key(|(buffer, _)| {
 6474                buffer.read(cx).file().map(|f| f.path().clone())
 6475            });
 6476        })?;
 6477        if entries.is_empty() {
 6478            return Ok(());
 6479        }
 6480
 6481        // If the project transaction's edits are all contained within this editor, then
 6482        // avoid opening a new editor to display them.
 6483
 6484        if let [(buffer, transaction)] = &*entries {
 6485            let excerpt = editor.update(cx, |editor, cx| {
 6486                editor
 6487                    .buffer()
 6488                    .read(cx)
 6489                    .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6490            })?;
 6491            if let Some((_, excerpted_buffer, excerpt_range)) = excerpt
 6492                && excerpted_buffer == *buffer
 6493            {
 6494                let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6495                    let excerpt_range = excerpt_range.to_offset(buffer);
 6496                    buffer
 6497                        .edited_ranges_for_transaction::<usize>(transaction)
 6498                        .all(|range| {
 6499                            excerpt_range.start <= range.start && excerpt_range.end >= range.end
 6500                        })
 6501                })?;
 6502
 6503                if all_edits_within_excerpt {
 6504                    return Ok(());
 6505                }
 6506            }
 6507        }
 6508
 6509        let mut ranges_to_highlight = Vec::new();
 6510        let excerpt_buffer = cx.new(|cx| {
 6511            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6512            for (buffer_handle, transaction) in &entries {
 6513                let edited_ranges = buffer_handle
 6514                    .read(cx)
 6515                    .edited_ranges_for_transaction::<Point>(transaction)
 6516                    .collect::<Vec<_>>();
 6517                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6518                    PathKey::for_buffer(buffer_handle, cx),
 6519                    buffer_handle.clone(),
 6520                    edited_ranges,
 6521                    multibuffer_context_lines(cx),
 6522                    cx,
 6523                );
 6524
 6525                ranges_to_highlight.extend(ranges);
 6526            }
 6527            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6528            multibuffer
 6529        })?;
 6530
 6531        workspace.update_in(cx, |workspace, window, cx| {
 6532            let project = workspace.project().clone();
 6533            let editor =
 6534                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6535            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6536            editor.update(cx, |editor, cx| {
 6537                editor.highlight_background::<Self>(
 6538                    &ranges_to_highlight,
 6539                    |theme| theme.colors().editor_highlighted_line_background,
 6540                    cx,
 6541                );
 6542            });
 6543        })?;
 6544
 6545        Ok(())
 6546    }
 6547
 6548    pub fn clear_code_action_providers(&mut self) {
 6549        self.code_action_providers.clear();
 6550        self.available_code_actions.take();
 6551    }
 6552
 6553    pub fn add_code_action_provider(
 6554        &mut self,
 6555        provider: Rc<dyn CodeActionProvider>,
 6556        window: &mut Window,
 6557        cx: &mut Context<Self>,
 6558    ) {
 6559        if self
 6560            .code_action_providers
 6561            .iter()
 6562            .any(|existing_provider| existing_provider.id() == provider.id())
 6563        {
 6564            return;
 6565        }
 6566
 6567        self.code_action_providers.push(provider);
 6568        self.refresh_code_actions(window, cx);
 6569    }
 6570
 6571    pub fn remove_code_action_provider(
 6572        &mut self,
 6573        id: Arc<str>,
 6574        window: &mut Window,
 6575        cx: &mut Context<Self>,
 6576    ) {
 6577        self.code_action_providers
 6578            .retain(|provider| provider.id() != id);
 6579        self.refresh_code_actions(window, cx);
 6580    }
 6581
 6582    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6583        !self.code_action_providers.is_empty()
 6584            && EditorSettings::get_global(cx).toolbar.code_actions
 6585    }
 6586
 6587    pub fn has_available_code_actions(&self) -> bool {
 6588        self.available_code_actions
 6589            .as_ref()
 6590            .is_some_and(|(_, actions)| !actions.is_empty())
 6591    }
 6592
 6593    fn render_inline_code_actions(
 6594        &self,
 6595        icon_size: ui::IconSize,
 6596        display_row: DisplayRow,
 6597        is_active: bool,
 6598        cx: &mut Context<Self>,
 6599    ) -> AnyElement {
 6600        let show_tooltip = !self.context_menu_visible();
 6601        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6602            .icon_size(icon_size)
 6603            .shape(ui::IconButtonShape::Square)
 6604            .icon_color(ui::Color::Hidden)
 6605            .toggle_state(is_active)
 6606            .when(show_tooltip, |this| {
 6607                this.tooltip({
 6608                    let focus_handle = self.focus_handle.clone();
 6609                    move |_window, cx| {
 6610                        Tooltip::for_action_in(
 6611                            "Toggle Code Actions",
 6612                            &ToggleCodeActions {
 6613                                deployed_from: None,
 6614                                quick_launch: false,
 6615                            },
 6616                            &focus_handle,
 6617                            cx,
 6618                        )
 6619                    }
 6620                })
 6621            })
 6622            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6623                window.focus(&editor.focus_handle(cx));
 6624                editor.toggle_code_actions(
 6625                    &crate::actions::ToggleCodeActions {
 6626                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6627                            display_row,
 6628                        )),
 6629                        quick_launch: false,
 6630                    },
 6631                    window,
 6632                    cx,
 6633                );
 6634            }))
 6635            .into_any_element()
 6636    }
 6637
 6638    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6639        &self.context_menu
 6640    }
 6641
 6642    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6643        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6644            cx.background_executor()
 6645                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6646                .await;
 6647
 6648            let (start_buffer, start, _, end, newest_selection) = this
 6649                .update(cx, |this, cx| {
 6650                    let newest_selection = this.selections.newest_anchor().clone();
 6651                    if newest_selection.head().diff_base_anchor.is_some() {
 6652                        return None;
 6653                    }
 6654                    let display_snapshot = this.display_snapshot(cx);
 6655                    let newest_selection_adjusted =
 6656                        this.selections.newest_adjusted(&display_snapshot);
 6657                    let buffer = this.buffer.read(cx);
 6658
 6659                    let (start_buffer, start) =
 6660                        buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6661                    let (end_buffer, end) =
 6662                        buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6663
 6664                    Some((start_buffer, start, end_buffer, end, newest_selection))
 6665                })?
 6666                .filter(|(start_buffer, _, end_buffer, _, _)| start_buffer == end_buffer)
 6667                .context(
 6668                    "Expected selection to lie in a single buffer when refreshing code actions",
 6669                )?;
 6670            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6671                let providers = this.code_action_providers.clone();
 6672                let tasks = this
 6673                    .code_action_providers
 6674                    .iter()
 6675                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6676                    .collect::<Vec<_>>();
 6677                (providers, tasks)
 6678            })?;
 6679
 6680            let mut actions = Vec::new();
 6681            for (provider, provider_actions) in
 6682                providers.into_iter().zip(future::join_all(tasks).await)
 6683            {
 6684                if let Some(provider_actions) = provider_actions.log_err() {
 6685                    actions.extend(provider_actions.into_iter().map(|action| {
 6686                        AvailableCodeAction {
 6687                            excerpt_id: newest_selection.start.excerpt_id,
 6688                            action,
 6689                            provider: provider.clone(),
 6690                        }
 6691                    }));
 6692                }
 6693            }
 6694
 6695            this.update(cx, |this, cx| {
 6696                this.available_code_actions = if actions.is_empty() {
 6697                    None
 6698                } else {
 6699                    Some((
 6700                        Location {
 6701                            buffer: start_buffer,
 6702                            range: start..end,
 6703                        },
 6704                        actions.into(),
 6705                    ))
 6706                };
 6707                cx.notify();
 6708            })
 6709        }));
 6710    }
 6711
 6712    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6713        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6714            self.show_git_blame_inline = false;
 6715
 6716            self.show_git_blame_inline_delay_task =
 6717                Some(cx.spawn_in(window, async move |this, cx| {
 6718                    cx.background_executor().timer(delay).await;
 6719
 6720                    this.update(cx, |this, cx| {
 6721                        this.show_git_blame_inline = true;
 6722                        cx.notify();
 6723                    })
 6724                    .log_err();
 6725                }));
 6726        }
 6727    }
 6728
 6729    pub fn blame_hover(&mut self, _: &BlameHover, window: &mut Window, cx: &mut Context<Self>) {
 6730        let snapshot = self.snapshot(window, cx);
 6731        let cursor = self
 6732            .selections
 6733            .newest::<Point>(&snapshot.display_snapshot)
 6734            .head();
 6735        let Some((buffer, point, _)) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)
 6736        else {
 6737            return;
 6738        };
 6739
 6740        let Some(blame) = self.blame.as_ref() else {
 6741            return;
 6742        };
 6743
 6744        let row_info = RowInfo {
 6745            buffer_id: Some(buffer.remote_id()),
 6746            buffer_row: Some(point.row),
 6747            ..Default::default()
 6748        };
 6749        let Some((buffer, blame_entry)) = blame
 6750            .update(cx, |blame, cx| blame.blame_for_rows(&[row_info], cx).next())
 6751            .flatten()
 6752        else {
 6753            return;
 6754        };
 6755
 6756        let anchor = self.selections.newest_anchor().head();
 6757        let position = self.to_pixel_point(anchor, &snapshot, window);
 6758        if let (Some(position), Some(last_bounds)) = (position, self.last_bounds) {
 6759            self.show_blame_popover(
 6760                buffer,
 6761                &blame_entry,
 6762                position + last_bounds.origin,
 6763                true,
 6764                cx,
 6765            );
 6766        };
 6767    }
 6768
 6769    fn show_blame_popover(
 6770        &mut self,
 6771        buffer: BufferId,
 6772        blame_entry: &BlameEntry,
 6773        position: gpui::Point<Pixels>,
 6774        ignore_timeout: bool,
 6775        cx: &mut Context<Self>,
 6776    ) {
 6777        if let Some(state) = &mut self.inline_blame_popover {
 6778            state.hide_task.take();
 6779        } else {
 6780            let blame_popover_delay = EditorSettings::get_global(cx).hover_popover_delay.0;
 6781            let blame_entry = blame_entry.clone();
 6782            let show_task = cx.spawn(async move |editor, cx| {
 6783                if !ignore_timeout {
 6784                    cx.background_executor()
 6785                        .timer(std::time::Duration::from_millis(blame_popover_delay))
 6786                        .await;
 6787                }
 6788                editor
 6789                    .update(cx, |editor, cx| {
 6790                        editor.inline_blame_popover_show_task.take();
 6791                        let Some(blame) = editor.blame.as_ref() else {
 6792                            return;
 6793                        };
 6794                        let blame = blame.read(cx);
 6795                        let details = blame.details_for_entry(buffer, &blame_entry);
 6796                        let markdown = cx.new(|cx| {
 6797                            Markdown::new(
 6798                                details
 6799                                    .as_ref()
 6800                                    .map(|message| message.message.clone())
 6801                                    .unwrap_or_default(),
 6802                                None,
 6803                                None,
 6804                                cx,
 6805                            )
 6806                        });
 6807                        editor.inline_blame_popover = Some(InlineBlamePopover {
 6808                            position,
 6809                            hide_task: None,
 6810                            popover_bounds: None,
 6811                            popover_state: InlineBlamePopoverState {
 6812                                scroll_handle: ScrollHandle::new(),
 6813                                commit_message: details,
 6814                                markdown,
 6815                            },
 6816                            keyboard_grace: ignore_timeout,
 6817                        });
 6818                        cx.notify();
 6819                    })
 6820                    .ok();
 6821            });
 6822            self.inline_blame_popover_show_task = Some(show_task);
 6823        }
 6824    }
 6825
 6826    fn hide_blame_popover(&mut self, ignore_timeout: bool, cx: &mut Context<Self>) -> bool {
 6827        self.inline_blame_popover_show_task.take();
 6828        if let Some(state) = &mut self.inline_blame_popover {
 6829            let hide_task = cx.spawn(async move |editor, cx| {
 6830                if !ignore_timeout {
 6831                    cx.background_executor()
 6832                        .timer(std::time::Duration::from_millis(100))
 6833                        .await;
 6834                }
 6835                editor
 6836                    .update(cx, |editor, cx| {
 6837                        editor.inline_blame_popover.take();
 6838                        cx.notify();
 6839                    })
 6840                    .ok();
 6841            });
 6842            state.hide_task = Some(hide_task);
 6843            true
 6844        } else {
 6845            false
 6846        }
 6847    }
 6848
 6849    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 6850        if self.pending_rename.is_some() {
 6851            return None;
 6852        }
 6853
 6854        let provider = self.semantics_provider.clone()?;
 6855        let buffer = self.buffer.read(cx);
 6856        let newest_selection = self.selections.newest_anchor().clone();
 6857        let cursor_position = newest_selection.head();
 6858        let (cursor_buffer, cursor_buffer_position) =
 6859            buffer.text_anchor_for_position(cursor_position, cx)?;
 6860        let (tail_buffer, tail_buffer_position) =
 6861            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 6862        if cursor_buffer != tail_buffer {
 6863            return None;
 6864        }
 6865
 6866        let snapshot = cursor_buffer.read(cx).snapshot();
 6867        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position, None);
 6868        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position, None);
 6869        if start_word_range != end_word_range {
 6870            self.document_highlights_task.take();
 6871            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6872            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6873            return None;
 6874        }
 6875
 6876        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce.0;
 6877        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6878            cx.background_executor()
 6879                .timer(Duration::from_millis(debounce))
 6880                .await;
 6881
 6882            let highlights = if let Some(highlights) = cx
 6883                .update(|cx| {
 6884                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 6885                })
 6886                .ok()
 6887                .flatten()
 6888            {
 6889                highlights.await.log_err()
 6890            } else {
 6891                None
 6892            };
 6893
 6894            if let Some(highlights) = highlights {
 6895                this.update(cx, |this, cx| {
 6896                    if this.pending_rename.is_some() {
 6897                        return;
 6898                    }
 6899
 6900                    let buffer = this.buffer.read(cx);
 6901                    if buffer
 6902                        .text_anchor_for_position(cursor_position, cx)
 6903                        .is_none_or(|(buffer, _)| buffer != cursor_buffer)
 6904                    {
 6905                        return;
 6906                    }
 6907
 6908                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 6909                    let mut write_ranges = Vec::new();
 6910                    let mut read_ranges = Vec::new();
 6911                    for highlight in highlights {
 6912                        let buffer_id = cursor_buffer.read(cx).remote_id();
 6913                        for (excerpt_id, excerpt_range) in buffer.excerpts_for_buffer(buffer_id, cx)
 6914                        {
 6915                            let start = highlight
 6916                                .range
 6917                                .start
 6918                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 6919                            let end = highlight
 6920                                .range
 6921                                .end
 6922                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6923                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6924                                continue;
 6925                            }
 6926
 6927                            let range =
 6928                                Anchor::range_in_buffer(excerpt_id, buffer_id, *start..*end);
 6929                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 6930                                write_ranges.push(range);
 6931                            } else {
 6932                                read_ranges.push(range);
 6933                            }
 6934                        }
 6935                    }
 6936
 6937                    this.highlight_background::<DocumentHighlightRead>(
 6938                        &read_ranges,
 6939                        |theme| theme.colors().editor_document_highlight_read_background,
 6940                        cx,
 6941                    );
 6942                    this.highlight_background::<DocumentHighlightWrite>(
 6943                        &write_ranges,
 6944                        |theme| theme.colors().editor_document_highlight_write_background,
 6945                        cx,
 6946                    );
 6947                    cx.notify();
 6948                })
 6949                .log_err();
 6950            }
 6951        }));
 6952        None
 6953    }
 6954
 6955    fn prepare_highlight_query_from_selection(
 6956        &mut self,
 6957        window: &Window,
 6958        cx: &mut Context<Editor>,
 6959    ) -> Option<(String, Range<Anchor>)> {
 6960        if matches!(self.mode, EditorMode::SingleLine) {
 6961            return None;
 6962        }
 6963        if !EditorSettings::get_global(cx).selection_highlight {
 6964            return None;
 6965        }
 6966        if self.selections.count() != 1 || self.selections.line_mode() {
 6967            return None;
 6968        }
 6969        let snapshot = self.snapshot(window, cx);
 6970        let selection = self.selections.newest::<Point>(&snapshot);
 6971        // If the selection spans multiple rows OR it is empty
 6972        if selection.start.row != selection.end.row
 6973            || selection.start.column == selection.end.column
 6974        {
 6975            return None;
 6976        }
 6977        let selection_anchor_range = selection.range().to_anchors(snapshot.buffer_snapshot());
 6978        let query = snapshot
 6979            .buffer_snapshot()
 6980            .text_for_range(selection_anchor_range.clone())
 6981            .collect::<String>();
 6982        if query.trim().is_empty() {
 6983            return None;
 6984        }
 6985        Some((query, selection_anchor_range))
 6986    }
 6987
 6988    fn update_selection_occurrence_highlights(
 6989        &mut self,
 6990        query_text: String,
 6991        query_range: Range<Anchor>,
 6992        multi_buffer_range_to_query: Range<Point>,
 6993        use_debounce: bool,
 6994        window: &mut Window,
 6995        cx: &mut Context<Editor>,
 6996    ) -> Task<()> {
 6997        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6998        cx.spawn_in(window, async move |editor, cx| {
 6999            if use_debounce {
 7000                cx.background_executor()
 7001                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 7002                    .await;
 7003            }
 7004            let match_task = cx.background_spawn(async move {
 7005                let buffer_ranges = multi_buffer_snapshot
 7006                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 7007                    .into_iter()
 7008                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 7009                let mut match_ranges = Vec::new();
 7010                let Ok(regex) = project::search::SearchQuery::text(
 7011                    query_text.clone(),
 7012                    false,
 7013                    false,
 7014                    false,
 7015                    Default::default(),
 7016                    Default::default(),
 7017                    false,
 7018                    None,
 7019                ) else {
 7020                    return Vec::default();
 7021                };
 7022                let query_range = query_range.to_anchors(&multi_buffer_snapshot);
 7023                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 7024                    match_ranges.extend(
 7025                        regex
 7026                            .search(
 7027                                buffer_snapshot,
 7028                                Some(search_range.start.0..search_range.end.0),
 7029                            )
 7030                            .await
 7031                            .into_iter()
 7032                            .filter_map(|match_range| {
 7033                                let match_start = buffer_snapshot
 7034                                    .anchor_after(search_range.start + match_range.start);
 7035                                let match_end = buffer_snapshot
 7036                                    .anchor_before(search_range.start + match_range.end);
 7037                                let match_anchor_range = Anchor::range_in_buffer(
 7038                                    excerpt_id,
 7039                                    buffer_snapshot.remote_id(),
 7040                                    match_start..match_end,
 7041                                );
 7042                                (match_anchor_range != query_range).then_some(match_anchor_range)
 7043                            }),
 7044                    );
 7045                }
 7046                match_ranges
 7047            });
 7048            let match_ranges = match_task.await;
 7049            editor
 7050                .update_in(cx, |editor, _, cx| {
 7051                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 7052                    if !match_ranges.is_empty() {
 7053                        editor.highlight_background::<SelectedTextHighlight>(
 7054                            &match_ranges,
 7055                            |theme| theme.colors().editor_document_highlight_bracket_background,
 7056                            cx,
 7057                        )
 7058                    }
 7059                })
 7060                .log_err();
 7061        })
 7062    }
 7063
 7064    fn refresh_single_line_folds(&mut self, window: &mut Window, cx: &mut Context<Editor>) {
 7065        struct NewlineFold;
 7066        let type_id = std::any::TypeId::of::<NewlineFold>();
 7067        if !self.mode.is_single_line() {
 7068            return;
 7069        }
 7070        let snapshot = self.snapshot(window, cx);
 7071        if snapshot.buffer_snapshot().max_point().row == 0 {
 7072            return;
 7073        }
 7074        let task = cx.background_spawn(async move {
 7075            let new_newlines = snapshot
 7076                .buffer_chars_at(MultiBufferOffset(0))
 7077                .filter_map(|(c, i)| {
 7078                    if c == '\n' {
 7079                        Some(
 7080                            snapshot.buffer_snapshot().anchor_after(i)
 7081                                ..snapshot.buffer_snapshot().anchor_before(i + 1usize),
 7082                        )
 7083                    } else {
 7084                        None
 7085                    }
 7086                })
 7087                .collect::<Vec<_>>();
 7088            let existing_newlines = snapshot
 7089                .folds_in_range(MultiBufferOffset(0)..snapshot.buffer_snapshot().len())
 7090                .filter_map(|fold| {
 7091                    if fold.placeholder.type_tag == Some(type_id) {
 7092                        Some(fold.range.start..fold.range.end)
 7093                    } else {
 7094                        None
 7095                    }
 7096                })
 7097                .collect::<Vec<_>>();
 7098
 7099            (new_newlines, existing_newlines)
 7100        });
 7101        self.folding_newlines = cx.spawn(async move |this, cx| {
 7102            let (new_newlines, existing_newlines) = task.await;
 7103            if new_newlines == existing_newlines {
 7104                return;
 7105            }
 7106            let placeholder = FoldPlaceholder {
 7107                render: Arc::new(move |_, _, cx| {
 7108                    div()
 7109                        .bg(cx.theme().status().hint_background)
 7110                        .border_b_1()
 7111                        .size_full()
 7112                        .font(ThemeSettings::get_global(cx).buffer_font.clone())
 7113                        .border_color(cx.theme().status().hint)
 7114                        .child("\\n")
 7115                        .into_any()
 7116                }),
 7117                constrain_width: false,
 7118                merge_adjacent: false,
 7119                type_tag: Some(type_id),
 7120            };
 7121            let creases = new_newlines
 7122                .into_iter()
 7123                .map(|range| Crease::simple(range, placeholder.clone()))
 7124                .collect();
 7125            this.update(cx, |this, cx| {
 7126                this.display_map.update(cx, |display_map, cx| {
 7127                    display_map.remove_folds_with_type(existing_newlines, type_id, cx);
 7128                    display_map.fold(creases, cx);
 7129                });
 7130            })
 7131            .ok();
 7132        });
 7133    }
 7134
 7135    fn refresh_selected_text_highlights(
 7136        &mut self,
 7137        on_buffer_edit: bool,
 7138        window: &mut Window,
 7139        cx: &mut Context<Editor>,
 7140    ) {
 7141        let Some((query_text, query_range)) =
 7142            self.prepare_highlight_query_from_selection(window, cx)
 7143        else {
 7144            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 7145            self.quick_selection_highlight_task.take();
 7146            self.debounced_selection_highlight_task.take();
 7147            return;
 7148        };
 7149        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 7150        if on_buffer_edit
 7151            || self
 7152                .quick_selection_highlight_task
 7153                .as_ref()
 7154                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7155        {
 7156            let multi_buffer_visible_start = self
 7157                .scroll_manager
 7158                .anchor()
 7159                .anchor
 7160                .to_point(&multi_buffer_snapshot);
 7161            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 7162                multi_buffer_visible_start
 7163                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 7164                Bias::Left,
 7165            );
 7166            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 7167            self.quick_selection_highlight_task = Some((
 7168                query_range.clone(),
 7169                self.update_selection_occurrence_highlights(
 7170                    query_text.clone(),
 7171                    query_range.clone(),
 7172                    multi_buffer_visible_range,
 7173                    false,
 7174                    window,
 7175                    cx,
 7176                ),
 7177            ));
 7178        }
 7179        if on_buffer_edit
 7180            || self
 7181                .debounced_selection_highlight_task
 7182                .as_ref()
 7183                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7184        {
 7185            let multi_buffer_start = multi_buffer_snapshot
 7186                .anchor_before(MultiBufferOffset(0))
 7187                .to_point(&multi_buffer_snapshot);
 7188            let multi_buffer_end = multi_buffer_snapshot
 7189                .anchor_after(multi_buffer_snapshot.len())
 7190                .to_point(&multi_buffer_snapshot);
 7191            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 7192            self.debounced_selection_highlight_task = Some((
 7193                query_range.clone(),
 7194                self.update_selection_occurrence_highlights(
 7195                    query_text,
 7196                    query_range,
 7197                    multi_buffer_full_range,
 7198                    true,
 7199                    window,
 7200                    cx,
 7201                ),
 7202            ));
 7203        }
 7204    }
 7205
 7206    pub fn refresh_edit_prediction(
 7207        &mut self,
 7208        debounce: bool,
 7209        user_requested: bool,
 7210        window: &mut Window,
 7211        cx: &mut Context<Self>,
 7212    ) -> Option<()> {
 7213        if DisableAiSettings::get_global(cx).disable_ai {
 7214            return None;
 7215        }
 7216
 7217        let provider = self.edit_prediction_provider()?;
 7218        let cursor = self.selections.newest_anchor().head();
 7219        let (buffer, cursor_buffer_position) =
 7220            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7221
 7222        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 7223            self.discard_edit_prediction(false, cx);
 7224            return None;
 7225        }
 7226
 7227        self.update_visible_edit_prediction(window, cx);
 7228
 7229        if !user_requested
 7230            && (!self.should_show_edit_predictions()
 7231                || !self.is_focused(window)
 7232                || buffer.read(cx).is_empty())
 7233        {
 7234            self.discard_edit_prediction(false, cx);
 7235            return None;
 7236        }
 7237
 7238        provider.refresh(buffer, cursor_buffer_position, debounce, cx);
 7239        Some(())
 7240    }
 7241
 7242    fn show_edit_predictions_in_menu(&self) -> bool {
 7243        match self.edit_prediction_settings {
 7244            EditPredictionSettings::Disabled => false,
 7245            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 7246        }
 7247    }
 7248
 7249    pub fn edit_predictions_enabled(&self) -> bool {
 7250        match self.edit_prediction_settings {
 7251            EditPredictionSettings::Disabled => false,
 7252            EditPredictionSettings::Enabled { .. } => true,
 7253        }
 7254    }
 7255
 7256    fn edit_prediction_requires_modifier(&self) -> bool {
 7257        match self.edit_prediction_settings {
 7258            EditPredictionSettings::Disabled => false,
 7259            EditPredictionSettings::Enabled {
 7260                preview_requires_modifier,
 7261                ..
 7262            } => preview_requires_modifier,
 7263        }
 7264    }
 7265
 7266    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 7267        if self.edit_prediction_provider.is_none() || DisableAiSettings::get_global(cx).disable_ai {
 7268            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7269            self.discard_edit_prediction(false, cx);
 7270        } else {
 7271            let selection = self.selections.newest_anchor();
 7272            let cursor = selection.head();
 7273
 7274            if let Some((buffer, cursor_buffer_position)) =
 7275                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7276            {
 7277                self.edit_prediction_settings =
 7278                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7279            }
 7280        }
 7281    }
 7282
 7283    fn edit_prediction_settings_at_position(
 7284        &self,
 7285        buffer: &Entity<Buffer>,
 7286        buffer_position: language::Anchor,
 7287        cx: &App,
 7288    ) -> EditPredictionSettings {
 7289        if !self.mode.is_full()
 7290            || !self.show_edit_predictions_override.unwrap_or(true)
 7291            || self.edit_predictions_disabled_in_scope(buffer, buffer_position, cx)
 7292        {
 7293            return EditPredictionSettings::Disabled;
 7294        }
 7295
 7296        let buffer = buffer.read(cx);
 7297
 7298        let file = buffer.file();
 7299
 7300        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 7301            return EditPredictionSettings::Disabled;
 7302        };
 7303
 7304        let by_provider = matches!(
 7305            self.menu_edit_predictions_policy,
 7306            MenuEditPredictionsPolicy::ByProvider
 7307        );
 7308
 7309        let show_in_menu = by_provider
 7310            && self
 7311                .edit_prediction_provider
 7312                .as_ref()
 7313                .is_some_and(|provider| provider.provider.show_completions_in_menu());
 7314
 7315        let preview_requires_modifier =
 7316            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 7317
 7318        EditPredictionSettings::Enabled {
 7319            show_in_menu,
 7320            preview_requires_modifier,
 7321        }
 7322    }
 7323
 7324    fn should_show_edit_predictions(&self) -> bool {
 7325        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 7326    }
 7327
 7328    pub fn edit_prediction_preview_is_active(&self) -> bool {
 7329        matches!(
 7330            self.edit_prediction_preview,
 7331            EditPredictionPreview::Active { .. }
 7332        )
 7333    }
 7334
 7335    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 7336        let cursor = self.selections.newest_anchor().head();
 7337        if let Some((buffer, cursor_position)) =
 7338            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7339        {
 7340            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 7341        } else {
 7342            false
 7343        }
 7344    }
 7345
 7346    pub fn supports_minimap(&self, cx: &App) -> bool {
 7347        !self.minimap_visibility.disabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton
 7348    }
 7349
 7350    fn edit_predictions_enabled_in_buffer(
 7351        &self,
 7352        buffer: &Entity<Buffer>,
 7353        buffer_position: language::Anchor,
 7354        cx: &App,
 7355    ) -> bool {
 7356        maybe!({
 7357            if self.read_only(cx) {
 7358                return Some(false);
 7359            }
 7360            let provider = self.edit_prediction_provider()?;
 7361            if !provider.is_enabled(buffer, buffer_position, cx) {
 7362                return Some(false);
 7363            }
 7364            let buffer = buffer.read(cx);
 7365            let Some(file) = buffer.file() else {
 7366                return Some(true);
 7367            };
 7368            let settings = all_language_settings(Some(file), cx);
 7369            Some(settings.edit_predictions_enabled_for_file(file, cx))
 7370        })
 7371        .unwrap_or(false)
 7372    }
 7373
 7374    fn cycle_edit_prediction(
 7375        &mut self,
 7376        direction: Direction,
 7377        window: &mut Window,
 7378        cx: &mut Context<Self>,
 7379    ) -> Option<()> {
 7380        let provider = self.edit_prediction_provider()?;
 7381        let cursor = self.selections.newest_anchor().head();
 7382        let (buffer, cursor_buffer_position) =
 7383            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7384        if self.edit_predictions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 7385            return None;
 7386        }
 7387
 7388        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 7389        self.update_visible_edit_prediction(window, cx);
 7390
 7391        Some(())
 7392    }
 7393
 7394    pub fn show_edit_prediction(
 7395        &mut self,
 7396        _: &ShowEditPrediction,
 7397        window: &mut Window,
 7398        cx: &mut Context<Self>,
 7399    ) {
 7400        if !self.has_active_edit_prediction() {
 7401            self.refresh_edit_prediction(false, true, window, cx);
 7402            return;
 7403        }
 7404
 7405        self.update_visible_edit_prediction(window, cx);
 7406    }
 7407
 7408    pub fn display_cursor_names(
 7409        &mut self,
 7410        _: &DisplayCursorNames,
 7411        window: &mut Window,
 7412        cx: &mut Context<Self>,
 7413    ) {
 7414        self.show_cursor_names(window, cx);
 7415    }
 7416
 7417    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7418        self.show_cursor_names = true;
 7419        cx.notify();
 7420        cx.spawn_in(window, async move |this, cx| {
 7421            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 7422            this.update(cx, |this, cx| {
 7423                this.show_cursor_names = false;
 7424                cx.notify()
 7425            })
 7426            .ok()
 7427        })
 7428        .detach();
 7429    }
 7430
 7431    pub fn next_edit_prediction(
 7432        &mut self,
 7433        _: &NextEditPrediction,
 7434        window: &mut Window,
 7435        cx: &mut Context<Self>,
 7436    ) {
 7437        if self.has_active_edit_prediction() {
 7438            self.cycle_edit_prediction(Direction::Next, window, cx);
 7439        } else {
 7440            let is_copilot_disabled = self
 7441                .refresh_edit_prediction(false, true, window, cx)
 7442                .is_none();
 7443            if is_copilot_disabled {
 7444                cx.propagate();
 7445            }
 7446        }
 7447    }
 7448
 7449    pub fn previous_edit_prediction(
 7450        &mut self,
 7451        _: &PreviousEditPrediction,
 7452        window: &mut Window,
 7453        cx: &mut Context<Self>,
 7454    ) {
 7455        if self.has_active_edit_prediction() {
 7456            self.cycle_edit_prediction(Direction::Prev, window, cx);
 7457        } else {
 7458            let is_copilot_disabled = self
 7459                .refresh_edit_prediction(false, true, window, cx)
 7460                .is_none();
 7461            if is_copilot_disabled {
 7462                cx.propagate();
 7463            }
 7464        }
 7465    }
 7466
 7467    pub fn accept_edit_prediction(
 7468        &mut self,
 7469        _: &AcceptEditPrediction,
 7470        window: &mut Window,
 7471        cx: &mut Context<Self>,
 7472    ) {
 7473        if self.show_edit_predictions_in_menu() {
 7474            self.hide_context_menu(window, cx);
 7475        }
 7476
 7477        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7478            return;
 7479        };
 7480
 7481        match &active_edit_prediction.completion {
 7482            EditPrediction::MoveWithin { target, .. } => {
 7483                let target = *target;
 7484
 7485                if let Some(position_map) = &self.last_position_map {
 7486                    if position_map
 7487                        .visible_row_range
 7488                        .contains(&target.to_display_point(&position_map.snapshot).row())
 7489                        || !self.edit_prediction_requires_modifier()
 7490                    {
 7491                        self.unfold_ranges(&[target..target], true, false, cx);
 7492                        // Note that this is also done in vim's handler of the Tab action.
 7493                        self.change_selections(
 7494                            SelectionEffects::scroll(Autoscroll::newest()),
 7495                            window,
 7496                            cx,
 7497                            |selections| {
 7498                                selections.select_anchor_ranges([target..target]);
 7499                            },
 7500                        );
 7501                        self.clear_row_highlights::<EditPredictionPreview>();
 7502
 7503                        self.edit_prediction_preview
 7504                            .set_previous_scroll_position(None);
 7505                    } else {
 7506                        self.edit_prediction_preview
 7507                            .set_previous_scroll_position(Some(
 7508                                position_map.snapshot.scroll_anchor,
 7509                            ));
 7510
 7511                        self.highlight_rows::<EditPredictionPreview>(
 7512                            target..target,
 7513                            cx.theme().colors().editor_highlighted_line_background,
 7514                            RowHighlightOptions {
 7515                                autoscroll: true,
 7516                                ..Default::default()
 7517                            },
 7518                            cx,
 7519                        );
 7520                        self.request_autoscroll(Autoscroll::fit(), cx);
 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                if let Some(provider) = self.edit_prediction_provider() {
 7538                    provider.accept(cx);
 7539                }
 7540
 7541                // Store the transaction ID and selections before applying the edit
 7542                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 7543
 7544                let snapshot = self.buffer.read(cx).snapshot(cx);
 7545                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 7546
 7547                self.buffer.update(cx, |buffer, cx| {
 7548                    buffer.edit(edits.iter().cloned(), None, cx)
 7549                });
 7550
 7551                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 7552                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 7553                });
 7554
 7555                let selections = self.selections.disjoint_anchors_arc();
 7556                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 7557                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 7558                    if has_new_transaction {
 7559                        self.selection_history
 7560                            .insert_transaction(transaction_id_now, selections);
 7561                    }
 7562                }
 7563
 7564                self.update_visible_edit_prediction(window, cx);
 7565                if self.active_edit_prediction.is_none() {
 7566                    self.refresh_edit_prediction(true, true, window, cx);
 7567                }
 7568
 7569                cx.notify();
 7570            }
 7571        }
 7572
 7573        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 7574    }
 7575
 7576    pub fn accept_partial_edit_prediction(
 7577        &mut self,
 7578        _: &AcceptPartialEditPrediction,
 7579        window: &mut Window,
 7580        cx: &mut Context<Self>,
 7581    ) {
 7582        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7583            return;
 7584        };
 7585        if self.selections.count() != 1 {
 7586            return;
 7587        }
 7588
 7589        match &active_edit_prediction.completion {
 7590            EditPrediction::MoveWithin { target, .. } => {
 7591                let target = *target;
 7592                self.change_selections(
 7593                    SelectionEffects::scroll(Autoscroll::newest()),
 7594                    window,
 7595                    cx,
 7596                    |selections| {
 7597                        selections.select_anchor_ranges([target..target]);
 7598                    },
 7599                );
 7600            }
 7601            EditPrediction::MoveOutside { snapshot, target } => {
 7602                if let Some(workspace) = self.workspace() {
 7603                    Self::open_editor_at_anchor(snapshot, *target, &workspace, window, cx)
 7604                        .detach_and_log_err(cx);
 7605                }
 7606            }
 7607            EditPrediction::Edit { edits, .. } => {
 7608                self.report_edit_prediction_event(
 7609                    active_edit_prediction.completion_id.clone(),
 7610                    true,
 7611                    cx,
 7612                );
 7613
 7614                // Find an insertion that starts at the cursor position.
 7615                let snapshot = self.buffer.read(cx).snapshot(cx);
 7616                let cursor_offset = self
 7617                    .selections
 7618                    .newest::<MultiBufferOffset>(&self.display_snapshot(cx))
 7619                    .head();
 7620                let insertion = edits.iter().find_map(|(range, text)| {
 7621                    let range = range.to_offset(&snapshot);
 7622                    if range.is_empty() && range.start == cursor_offset {
 7623                        Some(text)
 7624                    } else {
 7625                        None
 7626                    }
 7627                });
 7628
 7629                if let Some(text) = insertion {
 7630                    let mut partial_completion = text
 7631                        .chars()
 7632                        .by_ref()
 7633                        .take_while(|c| c.is_alphabetic())
 7634                        .collect::<String>();
 7635                    if partial_completion.is_empty() {
 7636                        partial_completion = text
 7637                            .chars()
 7638                            .by_ref()
 7639                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7640                            .collect::<String>();
 7641                    }
 7642
 7643                    cx.emit(EditorEvent::InputHandled {
 7644                        utf16_range_to_replace: None,
 7645                        text: partial_completion.clone().into(),
 7646                    });
 7647
 7648                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 7649
 7650                    self.refresh_edit_prediction(true, true, window, cx);
 7651                    cx.notify();
 7652                } else {
 7653                    self.accept_edit_prediction(&Default::default(), window, cx);
 7654                }
 7655            }
 7656        }
 7657    }
 7658
 7659    fn discard_edit_prediction(
 7660        &mut self,
 7661        should_report_edit_prediction_event: bool,
 7662        cx: &mut Context<Self>,
 7663    ) -> bool {
 7664        if should_report_edit_prediction_event {
 7665            let completion_id = self
 7666                .active_edit_prediction
 7667                .as_ref()
 7668                .and_then(|active_completion| active_completion.completion_id.clone());
 7669
 7670            self.report_edit_prediction_event(completion_id, false, cx);
 7671        }
 7672
 7673        if let Some(provider) = self.edit_prediction_provider() {
 7674            provider.discard(cx);
 7675        }
 7676
 7677        self.take_active_edit_prediction(cx)
 7678    }
 7679
 7680    fn report_edit_prediction_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7681        let Some(provider) = self.edit_prediction_provider() else {
 7682            return;
 7683        };
 7684
 7685        let Some((_, buffer, _)) = self
 7686            .buffer
 7687            .read(cx)
 7688            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7689        else {
 7690            return;
 7691        };
 7692
 7693        let extension = buffer
 7694            .read(cx)
 7695            .file()
 7696            .and_then(|file| Some(file.path().extension()?.to_string()));
 7697
 7698        let event_type = match accepted {
 7699            true => "Edit Prediction Accepted",
 7700            false => "Edit Prediction Discarded",
 7701        };
 7702        telemetry::event!(
 7703            event_type,
 7704            provider = provider.name(),
 7705            prediction_id = id,
 7706            suggestion_accepted = accepted,
 7707            file_extension = extension,
 7708        );
 7709    }
 7710
 7711    fn open_editor_at_anchor(
 7712        snapshot: &language::BufferSnapshot,
 7713        target: language::Anchor,
 7714        workspace: &Entity<Workspace>,
 7715        window: &mut Window,
 7716        cx: &mut App,
 7717    ) -> Task<Result<()>> {
 7718        workspace.update(cx, |workspace, cx| {
 7719            let path = snapshot.file().map(|file| file.full_path(cx));
 7720            let Some(path) =
 7721                path.and_then(|path| workspace.project().read(cx).find_project_path(path, cx))
 7722            else {
 7723                return Task::ready(Err(anyhow::anyhow!("Project path not found")));
 7724            };
 7725            let target = text::ToPoint::to_point(&target, snapshot);
 7726            let item = workspace.open_path(path, None, true, window, cx);
 7727            window.spawn(cx, async move |cx| {
 7728                let Some(editor) = item.await?.downcast::<Editor>() else {
 7729                    return Ok(());
 7730                };
 7731                editor
 7732                    .update_in(cx, |editor, window, cx| {
 7733                        editor.go_to_singleton_buffer_point(target, window, cx);
 7734                    })
 7735                    .ok();
 7736                anyhow::Ok(())
 7737            })
 7738        })
 7739    }
 7740
 7741    pub fn has_active_edit_prediction(&self) -> bool {
 7742        self.active_edit_prediction.is_some()
 7743    }
 7744
 7745    fn take_active_edit_prediction(&mut self, cx: &mut Context<Self>) -> bool {
 7746        let Some(active_edit_prediction) = self.active_edit_prediction.take() else {
 7747            return false;
 7748        };
 7749
 7750        self.splice_inlays(&active_edit_prediction.inlay_ids, Default::default(), cx);
 7751        self.clear_highlights::<EditPredictionHighlight>(cx);
 7752        self.stale_edit_prediction_in_menu = Some(active_edit_prediction);
 7753        true
 7754    }
 7755
 7756    /// Returns true when we're displaying the edit prediction popover below the cursor
 7757    /// like we are not previewing and the LSP autocomplete menu is visible
 7758    /// or we are in `when_holding_modifier` mode.
 7759    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7760        if self.edit_prediction_preview_is_active()
 7761            || !self.show_edit_predictions_in_menu()
 7762            || !self.edit_predictions_enabled()
 7763        {
 7764            return false;
 7765        }
 7766
 7767        if self.has_visible_completions_menu() {
 7768            return true;
 7769        }
 7770
 7771        has_completion && self.edit_prediction_requires_modifier()
 7772    }
 7773
 7774    fn handle_modifiers_changed(
 7775        &mut self,
 7776        modifiers: Modifiers,
 7777        position_map: &PositionMap,
 7778        window: &mut Window,
 7779        cx: &mut Context<Self>,
 7780    ) {
 7781        // Ensure that the edit prediction preview is updated, even when not
 7782        // enabled, if there's an active edit prediction preview.
 7783        if self.show_edit_predictions_in_menu()
 7784            || matches!(
 7785                self.edit_prediction_preview,
 7786                EditPredictionPreview::Active { .. }
 7787            )
 7788        {
 7789            self.update_edit_prediction_preview(&modifiers, window, cx);
 7790        }
 7791
 7792        self.update_selection_mode(&modifiers, position_map, window, cx);
 7793
 7794        let mouse_position = window.mouse_position();
 7795        if !position_map.text_hitbox.is_hovered(window) {
 7796            return;
 7797        }
 7798
 7799        self.update_hovered_link(
 7800            position_map.point_for_position(mouse_position),
 7801            &position_map.snapshot,
 7802            modifiers,
 7803            window,
 7804            cx,
 7805        )
 7806    }
 7807
 7808    fn is_cmd_or_ctrl_pressed(modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7809        match EditorSettings::get_global(cx).multi_cursor_modifier {
 7810            MultiCursorModifier::Alt => modifiers.secondary(),
 7811            MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 7812        }
 7813    }
 7814
 7815    fn is_alt_pressed(modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7816        match EditorSettings::get_global(cx).multi_cursor_modifier {
 7817            MultiCursorModifier::Alt => modifiers.alt,
 7818            MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 7819        }
 7820    }
 7821
 7822    fn columnar_selection_mode(
 7823        modifiers: &Modifiers,
 7824        cx: &mut Context<Self>,
 7825    ) -> Option<ColumnarMode> {
 7826        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 7827            if Self::is_cmd_or_ctrl_pressed(modifiers, cx) {
 7828                Some(ColumnarMode::FromMouse)
 7829            } else if Self::is_alt_pressed(modifiers, cx) {
 7830                Some(ColumnarMode::FromSelection)
 7831            } else {
 7832                None
 7833            }
 7834        } else {
 7835            None
 7836        }
 7837    }
 7838
 7839    fn update_selection_mode(
 7840        &mut self,
 7841        modifiers: &Modifiers,
 7842        position_map: &PositionMap,
 7843        window: &mut Window,
 7844        cx: &mut Context<Self>,
 7845    ) {
 7846        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 7847            return;
 7848        };
 7849        if self.selections.pending_anchor().is_none() {
 7850            return;
 7851        }
 7852
 7853        let mouse_position = window.mouse_position();
 7854        let point_for_position = position_map.point_for_position(mouse_position);
 7855        let position = point_for_position.previous_valid;
 7856
 7857        self.select(
 7858            SelectPhase::BeginColumnar {
 7859                position,
 7860                reset: false,
 7861                mode,
 7862                goal_column: point_for_position.exact_unclipped.column(),
 7863            },
 7864            window,
 7865            cx,
 7866        );
 7867    }
 7868
 7869    fn update_edit_prediction_preview(
 7870        &mut self,
 7871        modifiers: &Modifiers,
 7872        window: &mut Window,
 7873        cx: &mut Context<Self>,
 7874    ) {
 7875        let mut modifiers_held = false;
 7876        if let Some(accept_keystroke) = self
 7877            .accept_edit_prediction_keybind(false, window, cx)
 7878            .keystroke()
 7879        {
 7880            modifiers_held = modifiers_held
 7881                || (accept_keystroke.modifiers() == modifiers
 7882                    && accept_keystroke.modifiers().modified());
 7883        };
 7884        if let Some(accept_partial_keystroke) = self
 7885            .accept_edit_prediction_keybind(true, window, cx)
 7886            .keystroke()
 7887        {
 7888            modifiers_held = modifiers_held
 7889                || (accept_partial_keystroke.modifiers() == modifiers
 7890                    && accept_partial_keystroke.modifiers().modified());
 7891        }
 7892
 7893        if modifiers_held {
 7894            if matches!(
 7895                self.edit_prediction_preview,
 7896                EditPredictionPreview::Inactive { .. }
 7897            ) {
 7898                if let Some(provider) = self.edit_prediction_provider.as_ref() {
 7899                    provider.provider.did_show(cx)
 7900                }
 7901
 7902                self.edit_prediction_preview = EditPredictionPreview::Active {
 7903                    previous_scroll_position: None,
 7904                    since: Instant::now(),
 7905                };
 7906
 7907                self.update_visible_edit_prediction(window, cx);
 7908                cx.notify();
 7909            }
 7910        } else if let EditPredictionPreview::Active {
 7911            previous_scroll_position,
 7912            since,
 7913        } = self.edit_prediction_preview
 7914        {
 7915            if let (Some(previous_scroll_position), Some(position_map)) =
 7916                (previous_scroll_position, self.last_position_map.as_ref())
 7917            {
 7918                self.set_scroll_position(
 7919                    previous_scroll_position
 7920                        .scroll_position(&position_map.snapshot.display_snapshot),
 7921                    window,
 7922                    cx,
 7923                );
 7924            }
 7925
 7926            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 7927                released_too_fast: since.elapsed() < Duration::from_millis(200),
 7928            };
 7929            self.clear_row_highlights::<EditPredictionPreview>();
 7930            self.update_visible_edit_prediction(window, cx);
 7931            cx.notify();
 7932        }
 7933    }
 7934
 7935    fn update_visible_edit_prediction(
 7936        &mut self,
 7937        _window: &mut Window,
 7938        cx: &mut Context<Self>,
 7939    ) -> Option<()> {
 7940        if DisableAiSettings::get_global(cx).disable_ai {
 7941            return None;
 7942        }
 7943
 7944        if self.ime_transaction.is_some() {
 7945            self.discard_edit_prediction(false, cx);
 7946            return None;
 7947        }
 7948
 7949        let selection = self.selections.newest_anchor();
 7950        let cursor = selection.head();
 7951        let multibuffer = self.buffer.read(cx).snapshot(cx);
 7952        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 7953        let excerpt_id = cursor.excerpt_id;
 7954
 7955        let show_in_menu = self.show_edit_predictions_in_menu();
 7956        let completions_menu_has_precedence = !show_in_menu
 7957            && (self.context_menu.borrow().is_some()
 7958                || (!self.completion_tasks.is_empty() && !self.has_active_edit_prediction()));
 7959
 7960        if completions_menu_has_precedence
 7961            || !offset_selection.is_empty()
 7962            || self
 7963                .active_edit_prediction
 7964                .as_ref()
 7965                .is_some_and(|completion| {
 7966                    let Some(invalidation_range) = completion.invalidation_range.as_ref() else {
 7967                        return false;
 7968                    };
 7969                    let invalidation_range = invalidation_range.to_offset(&multibuffer);
 7970                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 7971                    !invalidation_range.contains(&offset_selection.head())
 7972                })
 7973        {
 7974            self.discard_edit_prediction(false, cx);
 7975            return None;
 7976        }
 7977
 7978        self.take_active_edit_prediction(cx);
 7979        let Some(provider) = self.edit_prediction_provider() else {
 7980            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7981            return None;
 7982        };
 7983
 7984        let (buffer, cursor_buffer_position) =
 7985            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7986
 7987        self.edit_prediction_settings =
 7988            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7989
 7990        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 7991
 7992        if self.edit_prediction_indent_conflict {
 7993            let cursor_point = cursor.to_point(&multibuffer);
 7994
 7995            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 7996
 7997            if let Some((_, indent)) = indents.iter().next()
 7998                && indent.len == cursor_point.column
 7999            {
 8000                self.edit_prediction_indent_conflict = false;
 8001            }
 8002        }
 8003
 8004        let edit_prediction = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 8005
 8006        let (completion_id, edits, edit_preview) = match edit_prediction {
 8007            edit_prediction::EditPrediction::Local {
 8008                id,
 8009                edits,
 8010                edit_preview,
 8011            } => (id, edits, edit_preview),
 8012            edit_prediction::EditPrediction::Jump {
 8013                id,
 8014                snapshot,
 8015                target,
 8016            } => {
 8017                self.stale_edit_prediction_in_menu = None;
 8018                self.active_edit_prediction = Some(EditPredictionState {
 8019                    inlay_ids: vec![],
 8020                    completion: EditPrediction::MoveOutside { snapshot, target },
 8021                    completion_id: id,
 8022                    invalidation_range: None,
 8023                });
 8024                cx.notify();
 8025                return Some(());
 8026            }
 8027        };
 8028
 8029        let edits = edits
 8030            .into_iter()
 8031            .flat_map(|(range, new_text)| {
 8032                Some((
 8033                    multibuffer.anchor_range_in_excerpt(excerpt_id, range)?,
 8034                    new_text,
 8035                ))
 8036            })
 8037            .collect::<Vec<_>>();
 8038        if edits.is_empty() {
 8039            return None;
 8040        }
 8041
 8042        let first_edit_start = edits.first().unwrap().0.start;
 8043        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 8044        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 8045
 8046        let last_edit_end = edits.last().unwrap().0.end;
 8047        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 8048        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 8049
 8050        let cursor_row = cursor.to_point(&multibuffer).row;
 8051
 8052        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 8053
 8054        let mut inlay_ids = Vec::new();
 8055        let invalidation_row_range;
 8056        let move_invalidation_row_range = if cursor_row < edit_start_row {
 8057            Some(cursor_row..edit_end_row)
 8058        } else if cursor_row > edit_end_row {
 8059            Some(edit_start_row..cursor_row)
 8060        } else {
 8061            None
 8062        };
 8063        let supports_jump = self
 8064            .edit_prediction_provider
 8065            .as_ref()
 8066            .map(|provider| provider.provider.supports_jump_to_edit())
 8067            .unwrap_or(true);
 8068
 8069        let is_move = supports_jump
 8070            && (move_invalidation_row_range.is_some() || self.edit_predictions_hidden_for_vim_mode);
 8071        let completion = if is_move {
 8072            invalidation_row_range =
 8073                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 8074            let target = first_edit_start;
 8075            EditPrediction::MoveWithin { target, snapshot }
 8076        } else {
 8077            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 8078                && !self.edit_predictions_hidden_for_vim_mode;
 8079
 8080            if show_completions_in_buffer {
 8081                if let Some(provider) = &self.edit_prediction_provider {
 8082                    provider.provider.did_show(cx);
 8083                }
 8084                if edits
 8085                    .iter()
 8086                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 8087                {
 8088                    let mut inlays = Vec::new();
 8089                    for (range, new_text) in &edits {
 8090                        let inlay = Inlay::edit_prediction(
 8091                            post_inc(&mut self.next_inlay_id),
 8092                            range.start,
 8093                            new_text.as_ref(),
 8094                        );
 8095                        inlay_ids.push(inlay.id);
 8096                        inlays.push(inlay);
 8097                    }
 8098
 8099                    self.splice_inlays(&[], inlays, cx);
 8100                } else {
 8101                    let background_color = cx.theme().status().deleted_background;
 8102                    self.highlight_text::<EditPredictionHighlight>(
 8103                        edits.iter().map(|(range, _)| range.clone()).collect(),
 8104                        HighlightStyle {
 8105                            background_color: Some(background_color),
 8106                            ..Default::default()
 8107                        },
 8108                        cx,
 8109                    );
 8110                }
 8111            }
 8112
 8113            invalidation_row_range = edit_start_row..edit_end_row;
 8114
 8115            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 8116                if provider.show_tab_accept_marker() {
 8117                    EditDisplayMode::TabAccept
 8118                } else {
 8119                    EditDisplayMode::Inline
 8120                }
 8121            } else {
 8122                EditDisplayMode::DiffPopover
 8123            };
 8124
 8125            EditPrediction::Edit {
 8126                edits,
 8127                edit_preview,
 8128                display_mode,
 8129                snapshot,
 8130            }
 8131        };
 8132
 8133        let invalidation_range = multibuffer
 8134            .anchor_before(Point::new(invalidation_row_range.start, 0))
 8135            ..multibuffer.anchor_after(Point::new(
 8136                invalidation_row_range.end,
 8137                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 8138            ));
 8139
 8140        self.stale_edit_prediction_in_menu = None;
 8141        self.active_edit_prediction = Some(EditPredictionState {
 8142            inlay_ids,
 8143            completion,
 8144            completion_id,
 8145            invalidation_range: Some(invalidation_range),
 8146        });
 8147
 8148        cx.notify();
 8149
 8150        Some(())
 8151    }
 8152
 8153    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn EditPredictionProviderHandle>> {
 8154        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 8155    }
 8156
 8157    fn clear_tasks(&mut self) {
 8158        self.tasks.clear()
 8159    }
 8160
 8161    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 8162        if self.tasks.insert(key, value).is_some() {
 8163            // This case should hopefully be rare, but just in case...
 8164            log::error!(
 8165                "multiple different run targets found on a single line, only the last target will be rendered"
 8166            )
 8167        }
 8168    }
 8169
 8170    /// Get all display points of breakpoints that will be rendered within editor
 8171    ///
 8172    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 8173    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 8174    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 8175    fn active_breakpoints(
 8176        &self,
 8177        range: Range<DisplayRow>,
 8178        window: &mut Window,
 8179        cx: &mut Context<Self>,
 8180    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 8181        let mut breakpoint_display_points = HashMap::default();
 8182
 8183        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 8184            return breakpoint_display_points;
 8185        };
 8186
 8187        let snapshot = self.snapshot(window, cx);
 8188
 8189        let multi_buffer_snapshot = snapshot.buffer_snapshot();
 8190        let Some(project) = self.project() else {
 8191            return breakpoint_display_points;
 8192        };
 8193
 8194        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 8195            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 8196
 8197        for (buffer_snapshot, range, excerpt_id) in
 8198            multi_buffer_snapshot.range_to_buffer_ranges(range)
 8199        {
 8200            let Some(buffer) = project
 8201                .read(cx)
 8202                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 8203            else {
 8204                continue;
 8205            };
 8206            let breakpoints = breakpoint_store.read(cx).breakpoints(
 8207                &buffer,
 8208                Some(
 8209                    buffer_snapshot.anchor_before(range.start)
 8210                        ..buffer_snapshot.anchor_after(range.end),
 8211                ),
 8212                buffer_snapshot,
 8213                cx,
 8214            );
 8215            for (breakpoint, state) in breakpoints {
 8216                let multi_buffer_anchor =
 8217                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 8218                let position = multi_buffer_anchor
 8219                    .to_point(&multi_buffer_snapshot)
 8220                    .to_display_point(&snapshot);
 8221
 8222                breakpoint_display_points.insert(
 8223                    position.row(),
 8224                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 8225                );
 8226            }
 8227        }
 8228
 8229        breakpoint_display_points
 8230    }
 8231
 8232    fn breakpoint_context_menu(
 8233        &self,
 8234        anchor: Anchor,
 8235        window: &mut Window,
 8236        cx: &mut Context<Self>,
 8237    ) -> Entity<ui::ContextMenu> {
 8238        let weak_editor = cx.weak_entity();
 8239        let focus_handle = self.focus_handle(cx);
 8240
 8241        let row = self
 8242            .buffer
 8243            .read(cx)
 8244            .snapshot(cx)
 8245            .summary_for_anchor::<Point>(&anchor)
 8246            .row;
 8247
 8248        let breakpoint = self
 8249            .breakpoint_at_row(row, window, cx)
 8250            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 8251
 8252        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 8253            "Edit Log Breakpoint"
 8254        } else {
 8255            "Set Log Breakpoint"
 8256        };
 8257
 8258        let condition_breakpoint_msg = if breakpoint
 8259            .as_ref()
 8260            .is_some_and(|bp| bp.1.condition.is_some())
 8261        {
 8262            "Edit Condition Breakpoint"
 8263        } else {
 8264            "Set Condition Breakpoint"
 8265        };
 8266
 8267        let hit_condition_breakpoint_msg = if breakpoint
 8268            .as_ref()
 8269            .is_some_and(|bp| bp.1.hit_condition.is_some())
 8270        {
 8271            "Edit Hit Condition Breakpoint"
 8272        } else {
 8273            "Set Hit Condition Breakpoint"
 8274        };
 8275
 8276        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 8277            "Unset Breakpoint"
 8278        } else {
 8279            "Set Breakpoint"
 8280        };
 8281
 8282        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 8283
 8284        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 8285            BreakpointState::Enabled => Some("Disable"),
 8286            BreakpointState::Disabled => Some("Enable"),
 8287        });
 8288
 8289        let (anchor, breakpoint) =
 8290            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 8291
 8292        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 8293            menu.on_blur_subscription(Subscription::new(|| {}))
 8294                .context(focus_handle)
 8295                .when(run_to_cursor, |this| {
 8296                    let weak_editor = weak_editor.clone();
 8297                    this.entry("Run to cursor", None, move |window, cx| {
 8298                        weak_editor
 8299                            .update(cx, |editor, cx| {
 8300                                editor.change_selections(
 8301                                    SelectionEffects::no_scroll(),
 8302                                    window,
 8303                                    cx,
 8304                                    |s| s.select_ranges([Point::new(row, 0)..Point::new(row, 0)]),
 8305                                );
 8306                            })
 8307                            .ok();
 8308
 8309                        window.dispatch_action(Box::new(RunToCursor), cx);
 8310                    })
 8311                    .separator()
 8312                })
 8313                .when_some(toggle_state_msg, |this, msg| {
 8314                    this.entry(msg, None, {
 8315                        let weak_editor = weak_editor.clone();
 8316                        let breakpoint = breakpoint.clone();
 8317                        move |_window, cx| {
 8318                            weak_editor
 8319                                .update(cx, |this, cx| {
 8320                                    this.edit_breakpoint_at_anchor(
 8321                                        anchor,
 8322                                        breakpoint.as_ref().clone(),
 8323                                        BreakpointEditAction::InvertState,
 8324                                        cx,
 8325                                    );
 8326                                })
 8327                                .log_err();
 8328                        }
 8329                    })
 8330                })
 8331                .entry(set_breakpoint_msg, None, {
 8332                    let weak_editor = weak_editor.clone();
 8333                    let breakpoint = breakpoint.clone();
 8334                    move |_window, cx| {
 8335                        weak_editor
 8336                            .update(cx, |this, cx| {
 8337                                this.edit_breakpoint_at_anchor(
 8338                                    anchor,
 8339                                    breakpoint.as_ref().clone(),
 8340                                    BreakpointEditAction::Toggle,
 8341                                    cx,
 8342                                );
 8343                            })
 8344                            .log_err();
 8345                    }
 8346                })
 8347                .entry(log_breakpoint_msg, None, {
 8348                    let breakpoint = breakpoint.clone();
 8349                    let weak_editor = weak_editor.clone();
 8350                    move |window, cx| {
 8351                        weak_editor
 8352                            .update(cx, |this, cx| {
 8353                                this.add_edit_breakpoint_block(
 8354                                    anchor,
 8355                                    breakpoint.as_ref(),
 8356                                    BreakpointPromptEditAction::Log,
 8357                                    window,
 8358                                    cx,
 8359                                );
 8360                            })
 8361                            .log_err();
 8362                    }
 8363                })
 8364                .entry(condition_breakpoint_msg, None, {
 8365                    let breakpoint = breakpoint.clone();
 8366                    let weak_editor = weak_editor.clone();
 8367                    move |window, cx| {
 8368                        weak_editor
 8369                            .update(cx, |this, cx| {
 8370                                this.add_edit_breakpoint_block(
 8371                                    anchor,
 8372                                    breakpoint.as_ref(),
 8373                                    BreakpointPromptEditAction::Condition,
 8374                                    window,
 8375                                    cx,
 8376                                );
 8377                            })
 8378                            .log_err();
 8379                    }
 8380                })
 8381                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 8382                    weak_editor
 8383                        .update(cx, |this, cx| {
 8384                            this.add_edit_breakpoint_block(
 8385                                anchor,
 8386                                breakpoint.as_ref(),
 8387                                BreakpointPromptEditAction::HitCondition,
 8388                                window,
 8389                                cx,
 8390                            );
 8391                        })
 8392                        .log_err();
 8393                })
 8394        })
 8395    }
 8396
 8397    fn render_breakpoint(
 8398        &self,
 8399        position: Anchor,
 8400        row: DisplayRow,
 8401        breakpoint: &Breakpoint,
 8402        state: Option<BreakpointSessionState>,
 8403        cx: &mut Context<Self>,
 8404    ) -> IconButton {
 8405        let is_rejected = state.is_some_and(|s| !s.verified);
 8406        // Is it a breakpoint that shows up when hovering over gutter?
 8407        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 8408            (false, false),
 8409            |PhantomBreakpointIndicator {
 8410                 is_active,
 8411                 display_row,
 8412                 collides_with_existing_breakpoint,
 8413             }| {
 8414                (
 8415                    is_active && display_row == row,
 8416                    collides_with_existing_breakpoint,
 8417                )
 8418            },
 8419        );
 8420
 8421        let (color, icon) = {
 8422            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 8423                (false, false) => ui::IconName::DebugBreakpoint,
 8424                (true, false) => ui::IconName::DebugLogBreakpoint,
 8425                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 8426                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 8427            };
 8428
 8429            let color = if is_phantom {
 8430                Color::Hint
 8431            } else if is_rejected {
 8432                Color::Disabled
 8433            } else {
 8434                Color::Debugger
 8435            };
 8436
 8437            (color, icon)
 8438        };
 8439
 8440        let breakpoint = Arc::from(breakpoint.clone());
 8441
 8442        let alt_as_text = gpui::Keystroke {
 8443            modifiers: Modifiers::secondary_key(),
 8444            ..Default::default()
 8445        };
 8446        let primary_action_text = if breakpoint.is_disabled() {
 8447            "Enable breakpoint"
 8448        } else if is_phantom && !collides_with_existing {
 8449            "Set breakpoint"
 8450        } else {
 8451            "Unset breakpoint"
 8452        };
 8453        let focus_handle = self.focus_handle.clone();
 8454
 8455        let meta = if is_rejected {
 8456            SharedString::from("No executable code is associated with this line.")
 8457        } else if collides_with_existing && !breakpoint.is_disabled() {
 8458            SharedString::from(format!(
 8459                "{alt_as_text}-click to disable,\nright-click for more options."
 8460            ))
 8461        } else {
 8462            SharedString::from("Right-click for more options.")
 8463        };
 8464        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 8465            .icon_size(IconSize::XSmall)
 8466            .size(ui::ButtonSize::None)
 8467            .when(is_rejected, |this| {
 8468                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 8469            })
 8470            .icon_color(color)
 8471            .style(ButtonStyle::Transparent)
 8472            .on_click(cx.listener({
 8473                move |editor, event: &ClickEvent, window, cx| {
 8474                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 8475                        BreakpointEditAction::InvertState
 8476                    } else {
 8477                        BreakpointEditAction::Toggle
 8478                    };
 8479
 8480                    window.focus(&editor.focus_handle(cx));
 8481                    editor.edit_breakpoint_at_anchor(
 8482                        position,
 8483                        breakpoint.as_ref().clone(),
 8484                        edit_action,
 8485                        cx,
 8486                    );
 8487                }
 8488            }))
 8489            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8490                editor.set_breakpoint_context_menu(
 8491                    row,
 8492                    Some(position),
 8493                    event.position(),
 8494                    window,
 8495                    cx,
 8496                );
 8497            }))
 8498            .tooltip(move |_window, cx| {
 8499                Tooltip::with_meta_in(
 8500                    primary_action_text,
 8501                    Some(&ToggleBreakpoint),
 8502                    meta.clone(),
 8503                    &focus_handle,
 8504                    cx,
 8505                )
 8506            })
 8507    }
 8508
 8509    fn build_tasks_context(
 8510        project: &Entity<Project>,
 8511        buffer: &Entity<Buffer>,
 8512        buffer_row: u32,
 8513        tasks: &Arc<RunnableTasks>,
 8514        cx: &mut Context<Self>,
 8515    ) -> Task<Option<task::TaskContext>> {
 8516        let position = Point::new(buffer_row, tasks.column);
 8517        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 8518        let location = Location {
 8519            buffer: buffer.clone(),
 8520            range: range_start..range_start,
 8521        };
 8522        // Fill in the environmental variables from the tree-sitter captures
 8523        let mut captured_task_variables = TaskVariables::default();
 8524        for (capture_name, value) in tasks.extra_variables.clone() {
 8525            captured_task_variables.insert(
 8526                task::VariableName::Custom(capture_name.into()),
 8527                value.clone(),
 8528            );
 8529        }
 8530        project.update(cx, |project, cx| {
 8531            project.task_store().update(cx, |task_store, cx| {
 8532                task_store.task_context_for_location(captured_task_variables, location, cx)
 8533            })
 8534        })
 8535    }
 8536
 8537    pub fn spawn_nearest_task(
 8538        &mut self,
 8539        action: &SpawnNearestTask,
 8540        window: &mut Window,
 8541        cx: &mut Context<Self>,
 8542    ) {
 8543        let Some((workspace, _)) = self.workspace.clone() else {
 8544            return;
 8545        };
 8546        let Some(project) = self.project.clone() else {
 8547            return;
 8548        };
 8549
 8550        // Try to find a closest, enclosing node using tree-sitter that has a task
 8551        let Some((buffer, buffer_row, tasks)) = self
 8552            .find_enclosing_node_task(cx)
 8553            // Or find the task that's closest in row-distance.
 8554            .or_else(|| self.find_closest_task(cx))
 8555        else {
 8556            return;
 8557        };
 8558
 8559        let reveal_strategy = action.reveal;
 8560        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 8561        cx.spawn_in(window, async move |_, cx| {
 8562            let context = task_context.await?;
 8563            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 8564
 8565            let resolved = &mut resolved_task.resolved;
 8566            resolved.reveal = reveal_strategy;
 8567
 8568            workspace
 8569                .update_in(cx, |workspace, window, cx| {
 8570                    workspace.schedule_resolved_task(
 8571                        task_source_kind,
 8572                        resolved_task,
 8573                        false,
 8574                        window,
 8575                        cx,
 8576                    );
 8577                })
 8578                .ok()
 8579        })
 8580        .detach();
 8581    }
 8582
 8583    fn find_closest_task(
 8584        &mut self,
 8585        cx: &mut Context<Self>,
 8586    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8587        let cursor_row = self
 8588            .selections
 8589            .newest_adjusted(&self.display_snapshot(cx))
 8590            .head()
 8591            .row;
 8592
 8593        let ((buffer_id, row), tasks) = self
 8594            .tasks
 8595            .iter()
 8596            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 8597
 8598        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 8599        let tasks = Arc::new(tasks.to_owned());
 8600        Some((buffer, *row, tasks))
 8601    }
 8602
 8603    fn find_enclosing_node_task(
 8604        &mut self,
 8605        cx: &mut Context<Self>,
 8606    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8607        let snapshot = self.buffer.read(cx).snapshot(cx);
 8608        let offset = self
 8609            .selections
 8610            .newest::<MultiBufferOffset>(&self.display_snapshot(cx))
 8611            .head();
 8612        let mut excerpt = snapshot.excerpt_containing(offset..offset)?;
 8613        let offset = excerpt.map_offset_to_buffer(offset);
 8614        let buffer_id = excerpt.buffer().remote_id();
 8615
 8616        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 8617        let mut cursor = layer.node().walk();
 8618
 8619        while cursor.goto_first_child_for_byte(offset.0).is_some() {
 8620            if cursor.node().end_byte() == offset.0 {
 8621                cursor.goto_next_sibling();
 8622            }
 8623        }
 8624
 8625        // Ascend to the smallest ancestor that contains the range and has a task.
 8626        loop {
 8627            let node = cursor.node();
 8628            let node_range = node.byte_range();
 8629            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 8630
 8631            // Check if this node contains our offset
 8632            if node_range.start <= offset.0 && node_range.end >= offset.0 {
 8633                // If it contains offset, check for task
 8634                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 8635                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 8636                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 8637                }
 8638            }
 8639
 8640            if !cursor.goto_parent() {
 8641                break;
 8642            }
 8643        }
 8644        None
 8645    }
 8646
 8647    fn render_run_indicator(
 8648        &self,
 8649        _style: &EditorStyle,
 8650        is_active: bool,
 8651        row: DisplayRow,
 8652        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 8653        cx: &mut Context<Self>,
 8654    ) -> IconButton {
 8655        let color = Color::Muted;
 8656        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 8657
 8658        IconButton::new(
 8659            ("run_indicator", row.0 as usize),
 8660            ui::IconName::PlayOutlined,
 8661        )
 8662        .shape(ui::IconButtonShape::Square)
 8663        .icon_size(IconSize::XSmall)
 8664        .icon_color(color)
 8665        .toggle_state(is_active)
 8666        .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 8667            let quick_launch = match e {
 8668                ClickEvent::Keyboard(_) => true,
 8669                ClickEvent::Mouse(e) => e.down.button == MouseButton::Left,
 8670            };
 8671
 8672            window.focus(&editor.focus_handle(cx));
 8673            editor.toggle_code_actions(
 8674                &ToggleCodeActions {
 8675                    deployed_from: Some(CodeActionSource::RunMenu(row)),
 8676                    quick_launch,
 8677                },
 8678                window,
 8679                cx,
 8680            );
 8681        }))
 8682        .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8683            editor.set_breakpoint_context_menu(row, position, event.position(), window, cx);
 8684        }))
 8685    }
 8686
 8687    pub fn context_menu_visible(&self) -> bool {
 8688        !self.edit_prediction_preview_is_active()
 8689            && self
 8690                .context_menu
 8691                .borrow()
 8692                .as_ref()
 8693                .is_some_and(|menu| menu.visible())
 8694    }
 8695
 8696    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 8697        self.context_menu
 8698            .borrow()
 8699            .as_ref()
 8700            .map(|menu| menu.origin())
 8701    }
 8702
 8703    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 8704        self.context_menu_options = Some(options);
 8705    }
 8706
 8707    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = px(24.);
 8708    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = px(2.);
 8709
 8710    fn render_edit_prediction_popover(
 8711        &mut self,
 8712        text_bounds: &Bounds<Pixels>,
 8713        content_origin: gpui::Point<Pixels>,
 8714        right_margin: Pixels,
 8715        editor_snapshot: &EditorSnapshot,
 8716        visible_row_range: Range<DisplayRow>,
 8717        scroll_top: ScrollOffset,
 8718        scroll_bottom: ScrollOffset,
 8719        line_layouts: &[LineWithInvisibles],
 8720        line_height: Pixels,
 8721        scroll_position: gpui::Point<ScrollOffset>,
 8722        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8723        newest_selection_head: Option<DisplayPoint>,
 8724        editor_width: Pixels,
 8725        style: &EditorStyle,
 8726        window: &mut Window,
 8727        cx: &mut App,
 8728    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8729        if self.mode().is_minimap() {
 8730            return None;
 8731        }
 8732        let active_edit_prediction = self.active_edit_prediction.as_ref()?;
 8733
 8734        if self.edit_prediction_visible_in_cursor_popover(true) {
 8735            return None;
 8736        }
 8737
 8738        match &active_edit_prediction.completion {
 8739            EditPrediction::MoveWithin { target, .. } => {
 8740                let target_display_point = target.to_display_point(editor_snapshot);
 8741
 8742                if self.edit_prediction_requires_modifier() {
 8743                    if !self.edit_prediction_preview_is_active() {
 8744                        return None;
 8745                    }
 8746
 8747                    self.render_edit_prediction_modifier_jump_popover(
 8748                        text_bounds,
 8749                        content_origin,
 8750                        visible_row_range,
 8751                        line_layouts,
 8752                        line_height,
 8753                        scroll_pixel_position,
 8754                        newest_selection_head,
 8755                        target_display_point,
 8756                        window,
 8757                        cx,
 8758                    )
 8759                } else {
 8760                    self.render_edit_prediction_eager_jump_popover(
 8761                        text_bounds,
 8762                        content_origin,
 8763                        editor_snapshot,
 8764                        visible_row_range,
 8765                        scroll_top,
 8766                        scroll_bottom,
 8767                        line_height,
 8768                        scroll_pixel_position,
 8769                        target_display_point,
 8770                        editor_width,
 8771                        window,
 8772                        cx,
 8773                    )
 8774                }
 8775            }
 8776            EditPrediction::Edit {
 8777                display_mode: EditDisplayMode::Inline,
 8778                ..
 8779            } => None,
 8780            EditPrediction::Edit {
 8781                display_mode: EditDisplayMode::TabAccept,
 8782                edits,
 8783                ..
 8784            } => {
 8785                let range = &edits.first()?.0;
 8786                let target_display_point = range.end.to_display_point(editor_snapshot);
 8787
 8788                self.render_edit_prediction_end_of_line_popover(
 8789                    "Accept",
 8790                    editor_snapshot,
 8791                    visible_row_range,
 8792                    target_display_point,
 8793                    line_height,
 8794                    scroll_pixel_position,
 8795                    content_origin,
 8796                    editor_width,
 8797                    window,
 8798                    cx,
 8799                )
 8800            }
 8801            EditPrediction::Edit {
 8802                edits,
 8803                edit_preview,
 8804                display_mode: EditDisplayMode::DiffPopover,
 8805                snapshot,
 8806            } => self.render_edit_prediction_diff_popover(
 8807                text_bounds,
 8808                content_origin,
 8809                right_margin,
 8810                editor_snapshot,
 8811                visible_row_range,
 8812                line_layouts,
 8813                line_height,
 8814                scroll_position,
 8815                scroll_pixel_position,
 8816                newest_selection_head,
 8817                editor_width,
 8818                style,
 8819                edits,
 8820                edit_preview,
 8821                snapshot,
 8822                window,
 8823                cx,
 8824            ),
 8825            EditPrediction::MoveOutside { snapshot, .. } => {
 8826                let file_name = snapshot
 8827                    .file()
 8828                    .map(|file| file.file_name(cx))
 8829                    .unwrap_or("untitled");
 8830                let mut element = self
 8831                    .render_edit_prediction_line_popover(
 8832                        format!("Jump to {file_name}"),
 8833                        Some(IconName::ZedPredict),
 8834                        window,
 8835                        cx,
 8836                    )
 8837                    .into_any();
 8838
 8839                let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8840                let origin_x = text_bounds.size.width / 2. - size.width / 2.;
 8841                let origin_y = text_bounds.size.height - size.height - px(30.);
 8842                let origin = text_bounds.origin + gpui::Point::new(origin_x, origin_y);
 8843                element.prepaint_at(origin, window, cx);
 8844
 8845                Some((element, origin))
 8846            }
 8847        }
 8848    }
 8849
 8850    fn render_edit_prediction_modifier_jump_popover(
 8851        &mut self,
 8852        text_bounds: &Bounds<Pixels>,
 8853        content_origin: gpui::Point<Pixels>,
 8854        visible_row_range: Range<DisplayRow>,
 8855        line_layouts: &[LineWithInvisibles],
 8856        line_height: Pixels,
 8857        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8858        newest_selection_head: Option<DisplayPoint>,
 8859        target_display_point: DisplayPoint,
 8860        window: &mut Window,
 8861        cx: &mut App,
 8862    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8863        let scrolled_content_origin =
 8864            content_origin - gpui::Point::new(scroll_pixel_position.x.into(), Pixels::ZERO);
 8865
 8866        const SCROLL_PADDING_Y: Pixels = px(12.);
 8867
 8868        if target_display_point.row() < visible_row_range.start {
 8869            return self.render_edit_prediction_scroll_popover(
 8870                |_| SCROLL_PADDING_Y,
 8871                IconName::ArrowUp,
 8872                visible_row_range,
 8873                line_layouts,
 8874                newest_selection_head,
 8875                scrolled_content_origin,
 8876                window,
 8877                cx,
 8878            );
 8879        } else if target_display_point.row() >= visible_row_range.end {
 8880            return self.render_edit_prediction_scroll_popover(
 8881                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 8882                IconName::ArrowDown,
 8883                visible_row_range,
 8884                line_layouts,
 8885                newest_selection_head,
 8886                scrolled_content_origin,
 8887                window,
 8888                cx,
 8889            );
 8890        }
 8891
 8892        const POLE_WIDTH: Pixels = px(2.);
 8893
 8894        let line_layout =
 8895            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 8896        let target_column = target_display_point.column() as usize;
 8897
 8898        let target_x = line_layout.x_for_index(target_column);
 8899        let target_y = (target_display_point.row().as_f64() * f64::from(line_height))
 8900            - scroll_pixel_position.y;
 8901
 8902        let flag_on_right = target_x < text_bounds.size.width / 2.;
 8903
 8904        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 8905        border_color.l += 0.001;
 8906
 8907        let mut element = v_flex()
 8908            .items_end()
 8909            .when(flag_on_right, |el| el.items_start())
 8910            .child(if flag_on_right {
 8911                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 8912                    .rounded_bl(px(0.))
 8913                    .rounded_tl(px(0.))
 8914                    .border_l_2()
 8915                    .border_color(border_color)
 8916            } else {
 8917                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 8918                    .rounded_br(px(0.))
 8919                    .rounded_tr(px(0.))
 8920                    .border_r_2()
 8921                    .border_color(border_color)
 8922            })
 8923            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 8924            .into_any();
 8925
 8926        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8927
 8928        let mut origin = scrolled_content_origin + point(target_x, target_y.into())
 8929            - point(
 8930                if flag_on_right {
 8931                    POLE_WIDTH
 8932                } else {
 8933                    size.width - POLE_WIDTH
 8934                },
 8935                size.height - line_height,
 8936            );
 8937
 8938        origin.x = origin.x.max(content_origin.x);
 8939
 8940        element.prepaint_at(origin, window, cx);
 8941
 8942        Some((element, origin))
 8943    }
 8944
 8945    fn render_edit_prediction_scroll_popover(
 8946        &mut self,
 8947        to_y: impl Fn(Size<Pixels>) -> Pixels,
 8948        scroll_icon: IconName,
 8949        visible_row_range: Range<DisplayRow>,
 8950        line_layouts: &[LineWithInvisibles],
 8951        newest_selection_head: Option<DisplayPoint>,
 8952        scrolled_content_origin: gpui::Point<Pixels>,
 8953        window: &mut Window,
 8954        cx: &mut App,
 8955    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8956        let mut element = self
 8957            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)
 8958            .into_any();
 8959
 8960        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8961
 8962        let cursor = newest_selection_head?;
 8963        let cursor_row_layout =
 8964            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 8965        let cursor_column = cursor.column() as usize;
 8966
 8967        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 8968
 8969        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 8970
 8971        element.prepaint_at(origin, window, cx);
 8972        Some((element, origin))
 8973    }
 8974
 8975    fn render_edit_prediction_eager_jump_popover(
 8976        &mut self,
 8977        text_bounds: &Bounds<Pixels>,
 8978        content_origin: gpui::Point<Pixels>,
 8979        editor_snapshot: &EditorSnapshot,
 8980        visible_row_range: Range<DisplayRow>,
 8981        scroll_top: ScrollOffset,
 8982        scroll_bottom: ScrollOffset,
 8983        line_height: Pixels,
 8984        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8985        target_display_point: DisplayPoint,
 8986        editor_width: Pixels,
 8987        window: &mut Window,
 8988        cx: &mut App,
 8989    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8990        if target_display_point.row().as_f64() < scroll_top {
 8991            let mut element = self
 8992                .render_edit_prediction_line_popover(
 8993                    "Jump to Edit",
 8994                    Some(IconName::ArrowUp),
 8995                    window,
 8996                    cx,
 8997                )
 8998                .into_any();
 8999
 9000            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9001            let offset = point(
 9002                (text_bounds.size.width - size.width) / 2.,
 9003                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 9004            );
 9005
 9006            let origin = text_bounds.origin + offset;
 9007            element.prepaint_at(origin, window, cx);
 9008            Some((element, origin))
 9009        } else if (target_display_point.row().as_f64() + 1.) > scroll_bottom {
 9010            let mut element = self
 9011                .render_edit_prediction_line_popover(
 9012                    "Jump to Edit",
 9013                    Some(IconName::ArrowDown),
 9014                    window,
 9015                    cx,
 9016                )
 9017                .into_any();
 9018
 9019            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9020            let offset = point(
 9021                (text_bounds.size.width - size.width) / 2.,
 9022                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 9023            );
 9024
 9025            let origin = text_bounds.origin + offset;
 9026            element.prepaint_at(origin, window, cx);
 9027            Some((element, origin))
 9028        } else {
 9029            self.render_edit_prediction_end_of_line_popover(
 9030                "Jump to Edit",
 9031                editor_snapshot,
 9032                visible_row_range,
 9033                target_display_point,
 9034                line_height,
 9035                scroll_pixel_position,
 9036                content_origin,
 9037                editor_width,
 9038                window,
 9039                cx,
 9040            )
 9041        }
 9042    }
 9043
 9044    fn render_edit_prediction_end_of_line_popover(
 9045        self: &mut Editor,
 9046        label: &'static str,
 9047        editor_snapshot: &EditorSnapshot,
 9048        visible_row_range: Range<DisplayRow>,
 9049        target_display_point: DisplayPoint,
 9050        line_height: Pixels,
 9051        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9052        content_origin: gpui::Point<Pixels>,
 9053        editor_width: Pixels,
 9054        window: &mut Window,
 9055        cx: &mut App,
 9056    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9057        let target_line_end = DisplayPoint::new(
 9058            target_display_point.row(),
 9059            editor_snapshot.line_len(target_display_point.row()),
 9060        );
 9061
 9062        let mut element = self
 9063            .render_edit_prediction_line_popover(label, None, window, cx)
 9064            .into_any();
 9065
 9066        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9067
 9068        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 9069
 9070        let start_point = content_origin - point(scroll_pixel_position.x.into(), Pixels::ZERO);
 9071        let mut origin = start_point
 9072            + line_origin
 9073            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 9074        origin.x = origin.x.max(content_origin.x);
 9075
 9076        let max_x = content_origin.x + editor_width - size.width;
 9077
 9078        if origin.x > max_x {
 9079            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 9080
 9081            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 9082                origin.y += offset;
 9083                IconName::ArrowUp
 9084            } else {
 9085                origin.y -= offset;
 9086                IconName::ArrowDown
 9087            };
 9088
 9089            element = self
 9090                .render_edit_prediction_line_popover(label, Some(icon), window, cx)
 9091                .into_any();
 9092
 9093            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9094
 9095            origin.x = content_origin.x + editor_width - size.width - px(2.);
 9096        }
 9097
 9098        element.prepaint_at(origin, window, cx);
 9099        Some((element, origin))
 9100    }
 9101
 9102    fn render_edit_prediction_diff_popover(
 9103        self: &Editor,
 9104        text_bounds: &Bounds<Pixels>,
 9105        content_origin: gpui::Point<Pixels>,
 9106        right_margin: Pixels,
 9107        editor_snapshot: &EditorSnapshot,
 9108        visible_row_range: Range<DisplayRow>,
 9109        line_layouts: &[LineWithInvisibles],
 9110        line_height: Pixels,
 9111        scroll_position: gpui::Point<ScrollOffset>,
 9112        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9113        newest_selection_head: Option<DisplayPoint>,
 9114        editor_width: Pixels,
 9115        style: &EditorStyle,
 9116        edits: &Vec<(Range<Anchor>, Arc<str>)>,
 9117        edit_preview: &Option<language::EditPreview>,
 9118        snapshot: &language::BufferSnapshot,
 9119        window: &mut Window,
 9120        cx: &mut App,
 9121    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9122        let edit_start = edits
 9123            .first()
 9124            .unwrap()
 9125            .0
 9126            .start
 9127            .to_display_point(editor_snapshot);
 9128        let edit_end = edits
 9129            .last()
 9130            .unwrap()
 9131            .0
 9132            .end
 9133            .to_display_point(editor_snapshot);
 9134
 9135        let is_visible = visible_row_range.contains(&edit_start.row())
 9136            || visible_row_range.contains(&edit_end.row());
 9137        if !is_visible {
 9138            return None;
 9139        }
 9140
 9141        let highlighted_edits = if let Some(edit_preview) = edit_preview.as_ref() {
 9142            crate::edit_prediction_edit_text(snapshot, edits, edit_preview, false, cx)
 9143        } else {
 9144            // Fallback for providers without edit_preview
 9145            crate::edit_prediction_fallback_text(edits, cx)
 9146        };
 9147
 9148        let styled_text = highlighted_edits.to_styled_text(&style.text);
 9149        let line_count = highlighted_edits.text.lines().count();
 9150
 9151        const BORDER_WIDTH: Pixels = px(1.);
 9152
 9153        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9154        let has_keybind = keybind.is_some();
 9155
 9156        let mut element = h_flex()
 9157            .items_start()
 9158            .child(
 9159                h_flex()
 9160                    .bg(cx.theme().colors().editor_background)
 9161                    .border(BORDER_WIDTH)
 9162                    .shadow_xs()
 9163                    .border_color(cx.theme().colors().border)
 9164                    .rounded_l_lg()
 9165                    .when(line_count > 1, |el| el.rounded_br_lg())
 9166                    .pr_1()
 9167                    .child(styled_text),
 9168            )
 9169            .child(
 9170                h_flex()
 9171                    .h(line_height + BORDER_WIDTH * 2.)
 9172                    .px_1p5()
 9173                    .gap_1()
 9174                    // Workaround: For some reason, there's a gap if we don't do this
 9175                    .ml(-BORDER_WIDTH)
 9176                    .shadow(vec![gpui::BoxShadow {
 9177                        color: gpui::black().opacity(0.05),
 9178                        offset: point(px(1.), px(1.)),
 9179                        blur_radius: px(2.),
 9180                        spread_radius: px(0.),
 9181                    }])
 9182                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 9183                    .border(BORDER_WIDTH)
 9184                    .border_color(cx.theme().colors().border)
 9185                    .rounded_r_lg()
 9186                    .id("edit_prediction_diff_popover_keybind")
 9187                    .when(!has_keybind, |el| {
 9188                        let status_colors = cx.theme().status();
 9189
 9190                        el.bg(status_colors.error_background)
 9191                            .border_color(status_colors.error.opacity(0.6))
 9192                            .child(Icon::new(IconName::Info).color(Color::Error))
 9193                            .cursor_default()
 9194                            .hoverable_tooltip(move |_window, cx| {
 9195                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9196                            })
 9197                    })
 9198                    .children(keybind),
 9199            )
 9200            .into_any();
 9201
 9202        let longest_row =
 9203            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 9204        let longest_line_width = if visible_row_range.contains(&longest_row) {
 9205            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 9206        } else {
 9207            layout_line(
 9208                longest_row,
 9209                editor_snapshot,
 9210                style,
 9211                editor_width,
 9212                |_| false,
 9213                window,
 9214                cx,
 9215            )
 9216            .width
 9217        };
 9218
 9219        let viewport_bounds =
 9220            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 9221                right: -right_margin,
 9222                ..Default::default()
 9223            });
 9224
 9225        let x_after_longest = Pixels::from(
 9226            ScrollPixelOffset::from(
 9227                text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X,
 9228            ) - scroll_pixel_position.x,
 9229        );
 9230
 9231        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9232
 9233        // Fully visible if it can be displayed within the window (allow overlapping other
 9234        // panes). However, this is only allowed if the popover starts within text_bounds.
 9235        let can_position_to_the_right = x_after_longest < text_bounds.right()
 9236            && x_after_longest + element_bounds.width < viewport_bounds.right();
 9237
 9238        let mut origin = if can_position_to_the_right {
 9239            point(
 9240                x_after_longest,
 9241                text_bounds.origin.y
 9242                    + Pixels::from(
 9243                        edit_start.row().as_f64() * ScrollPixelOffset::from(line_height)
 9244                            - scroll_pixel_position.y,
 9245                    ),
 9246            )
 9247        } else {
 9248            let cursor_row = newest_selection_head.map(|head| head.row());
 9249            let above_edit = edit_start
 9250                .row()
 9251                .0
 9252                .checked_sub(line_count as u32)
 9253                .map(DisplayRow);
 9254            let below_edit = Some(edit_end.row() + 1);
 9255            let above_cursor =
 9256                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 9257            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 9258
 9259            // Place the edit popover adjacent to the edit if there is a location
 9260            // available that is onscreen and does not obscure the cursor. Otherwise,
 9261            // place it adjacent to the cursor.
 9262            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 9263                .into_iter()
 9264                .flatten()
 9265                .find(|&start_row| {
 9266                    let end_row = start_row + line_count as u32;
 9267                    visible_row_range.contains(&start_row)
 9268                        && visible_row_range.contains(&end_row)
 9269                        && cursor_row
 9270                            .is_none_or(|cursor_row| !((start_row..end_row).contains(&cursor_row)))
 9271                })?;
 9272
 9273            content_origin
 9274                + point(
 9275                    Pixels::from(-scroll_pixel_position.x),
 9276                    Pixels::from(
 9277                        (row_target.as_f64() - scroll_position.y) * f64::from(line_height),
 9278                    ),
 9279                )
 9280        };
 9281
 9282        origin.x -= BORDER_WIDTH;
 9283
 9284        window.defer_draw(element, origin, 1);
 9285
 9286        // Do not return an element, since it will already be drawn due to defer_draw.
 9287        None
 9288    }
 9289
 9290    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 9291        px(30.)
 9292    }
 9293
 9294    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 9295        if self.read_only(cx) {
 9296            cx.theme().players().read_only()
 9297        } else {
 9298            self.style.as_ref().unwrap().local_player
 9299        }
 9300    }
 9301
 9302    fn render_edit_prediction_accept_keybind(
 9303        &self,
 9304        window: &mut Window,
 9305        cx: &mut App,
 9306    ) -> Option<AnyElement> {
 9307        let accept_binding = self.accept_edit_prediction_keybind(false, window, cx);
 9308        let accept_keystroke = accept_binding.keystroke()?;
 9309
 9310        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9311
 9312        let modifiers_color = if *accept_keystroke.modifiers() == window.modifiers() {
 9313            Color::Accent
 9314        } else {
 9315            Color::Muted
 9316        };
 9317
 9318        h_flex()
 9319            .px_0p5()
 9320            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 9321            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9322            .text_size(TextSize::XSmall.rems(cx))
 9323            .child(h_flex().children(ui::render_modifiers(
 9324                accept_keystroke.modifiers(),
 9325                PlatformStyle::platform(),
 9326                Some(modifiers_color),
 9327                Some(IconSize::XSmall.rems().into()),
 9328                true,
 9329            )))
 9330            .when(is_platform_style_mac, |parent| {
 9331                parent.child(accept_keystroke.key().to_string())
 9332            })
 9333            .when(!is_platform_style_mac, |parent| {
 9334                parent.child(
 9335                    Key::new(
 9336                        util::capitalize(accept_keystroke.key()),
 9337                        Some(Color::Default),
 9338                    )
 9339                    .size(Some(IconSize::XSmall.rems().into())),
 9340                )
 9341            })
 9342            .into_any()
 9343            .into()
 9344    }
 9345
 9346    fn render_edit_prediction_line_popover(
 9347        &self,
 9348        label: impl Into<SharedString>,
 9349        icon: Option<IconName>,
 9350        window: &mut Window,
 9351        cx: &mut App,
 9352    ) -> Stateful<Div> {
 9353        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 9354
 9355        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9356        let has_keybind = keybind.is_some();
 9357
 9358        h_flex()
 9359            .id("ep-line-popover")
 9360            .py_0p5()
 9361            .pl_1()
 9362            .pr(padding_right)
 9363            .gap_1()
 9364            .rounded_md()
 9365            .border_1()
 9366            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9367            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9368            .shadow_xs()
 9369            .when(!has_keybind, |el| {
 9370                let status_colors = cx.theme().status();
 9371
 9372                el.bg(status_colors.error_background)
 9373                    .border_color(status_colors.error.opacity(0.6))
 9374                    .pl_2()
 9375                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9376                    .cursor_default()
 9377                    .hoverable_tooltip(move |_window, cx| {
 9378                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9379                    })
 9380            })
 9381            .children(keybind)
 9382            .child(
 9383                Label::new(label)
 9384                    .size(LabelSize::Small)
 9385                    .when(!has_keybind, |el| {
 9386                        el.color(cx.theme().status().error.into()).strikethrough()
 9387                    }),
 9388            )
 9389            .when(!has_keybind, |el| {
 9390                el.child(
 9391                    h_flex().ml_1().child(
 9392                        Icon::new(IconName::Info)
 9393                            .size(IconSize::Small)
 9394                            .color(cx.theme().status().error.into()),
 9395                    ),
 9396                )
 9397            })
 9398            .when_some(icon, |element, icon| {
 9399                element.child(
 9400                    div()
 9401                        .mt(px(1.5))
 9402                        .child(Icon::new(icon).size(IconSize::Small)),
 9403                )
 9404            })
 9405    }
 9406
 9407    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 9408        let accent_color = cx.theme().colors().text_accent;
 9409        let editor_bg_color = cx.theme().colors().editor_background;
 9410        editor_bg_color.blend(accent_color.opacity(0.1))
 9411    }
 9412
 9413    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 9414        let accent_color = cx.theme().colors().text_accent;
 9415        let editor_bg_color = cx.theme().colors().editor_background;
 9416        editor_bg_color.blend(accent_color.opacity(0.6))
 9417    }
 9418    fn get_prediction_provider_icon_name(
 9419        provider: &Option<RegisteredEditPredictionProvider>,
 9420    ) -> IconName {
 9421        match provider {
 9422            Some(provider) => match provider.provider.name() {
 9423                "copilot" => IconName::Copilot,
 9424                "supermaven" => IconName::Supermaven,
 9425                _ => IconName::ZedPredict,
 9426            },
 9427            None => IconName::ZedPredict,
 9428        }
 9429    }
 9430
 9431    fn render_edit_prediction_cursor_popover(
 9432        &self,
 9433        min_width: Pixels,
 9434        max_width: Pixels,
 9435        cursor_point: Point,
 9436        style: &EditorStyle,
 9437        accept_keystroke: Option<&gpui::KeybindingKeystroke>,
 9438        _window: &Window,
 9439        cx: &mut Context<Editor>,
 9440    ) -> Option<AnyElement> {
 9441        let provider = self.edit_prediction_provider.as_ref()?;
 9442        let provider_icon = Self::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9443
 9444        let is_refreshing = provider.provider.is_refreshing(cx);
 9445
 9446        fn pending_completion_container(icon: IconName) -> Div {
 9447            h_flex().h_full().flex_1().gap_2().child(Icon::new(icon))
 9448        }
 9449
 9450        let completion = match &self.active_edit_prediction {
 9451            Some(prediction) => {
 9452                if !self.has_visible_completions_menu() {
 9453                    const RADIUS: Pixels = px(6.);
 9454                    const BORDER_WIDTH: Pixels = px(1.);
 9455
 9456                    return Some(
 9457                        h_flex()
 9458                            .elevation_2(cx)
 9459                            .border(BORDER_WIDTH)
 9460                            .border_color(cx.theme().colors().border)
 9461                            .when(accept_keystroke.is_none(), |el| {
 9462                                el.border_color(cx.theme().status().error)
 9463                            })
 9464                            .rounded(RADIUS)
 9465                            .rounded_tl(px(0.))
 9466                            .overflow_hidden()
 9467                            .child(div().px_1p5().child(match &prediction.completion {
 9468                                EditPrediction::MoveWithin { target, snapshot } => {
 9469                                    use text::ToPoint as _;
 9470                                    if target.text_anchor.to_point(snapshot).row > cursor_point.row
 9471                                    {
 9472                                        Icon::new(IconName::ZedPredictDown)
 9473                                    } else {
 9474                                        Icon::new(IconName::ZedPredictUp)
 9475                                    }
 9476                                }
 9477                                EditPrediction::MoveOutside { .. } => {
 9478                                    // TODO [zeta2] custom icon for external jump?
 9479                                    Icon::new(provider_icon)
 9480                                }
 9481                                EditPrediction::Edit { .. } => Icon::new(provider_icon),
 9482                            }))
 9483                            .child(
 9484                                h_flex()
 9485                                    .gap_1()
 9486                                    .py_1()
 9487                                    .px_2()
 9488                                    .rounded_r(RADIUS - BORDER_WIDTH)
 9489                                    .border_l_1()
 9490                                    .border_color(cx.theme().colors().border)
 9491                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9492                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 9493                                        el.child(
 9494                                            Label::new("Hold")
 9495                                                .size(LabelSize::Small)
 9496                                                .when(accept_keystroke.is_none(), |el| {
 9497                                                    el.strikethrough()
 9498                                                })
 9499                                                .line_height_style(LineHeightStyle::UiLabel),
 9500                                        )
 9501                                    })
 9502                                    .id("edit_prediction_cursor_popover_keybind")
 9503                                    .when(accept_keystroke.is_none(), |el| {
 9504                                        let status_colors = cx.theme().status();
 9505
 9506                                        el.bg(status_colors.error_background)
 9507                                            .border_color(status_colors.error.opacity(0.6))
 9508                                            .child(Icon::new(IconName::Info).color(Color::Error))
 9509                                            .cursor_default()
 9510                                            .hoverable_tooltip(move |_window, cx| {
 9511                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 9512                                                    .into()
 9513                                            })
 9514                                    })
 9515                                    .when_some(
 9516                                        accept_keystroke.as_ref(),
 9517                                        |el, accept_keystroke| {
 9518                                            el.child(h_flex().children(ui::render_modifiers(
 9519                                                accept_keystroke.modifiers(),
 9520                                                PlatformStyle::platform(),
 9521                                                Some(Color::Default),
 9522                                                Some(IconSize::XSmall.rems().into()),
 9523                                                false,
 9524                                            )))
 9525                                        },
 9526                                    ),
 9527                            )
 9528                            .into_any(),
 9529                    );
 9530                }
 9531
 9532                self.render_edit_prediction_cursor_popover_preview(
 9533                    prediction,
 9534                    cursor_point,
 9535                    style,
 9536                    cx,
 9537                )?
 9538            }
 9539
 9540            None if is_refreshing => match &self.stale_edit_prediction_in_menu {
 9541                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 9542                    stale_completion,
 9543                    cursor_point,
 9544                    style,
 9545                    cx,
 9546                )?,
 9547
 9548                None => pending_completion_container(provider_icon)
 9549                    .child(Label::new("...").size(LabelSize::Small)),
 9550            },
 9551
 9552            None => pending_completion_container(provider_icon)
 9553                .child(Label::new("...").size(LabelSize::Small)),
 9554        };
 9555
 9556        let completion = if is_refreshing || self.active_edit_prediction.is_none() {
 9557            completion
 9558                .with_animation(
 9559                    "loading-completion",
 9560                    Animation::new(Duration::from_secs(2))
 9561                        .repeat()
 9562                        .with_easing(pulsating_between(0.4, 0.8)),
 9563                    |label, delta| label.opacity(delta),
 9564                )
 9565                .into_any_element()
 9566        } else {
 9567            completion.into_any_element()
 9568        };
 9569
 9570        let has_completion = self.active_edit_prediction.is_some();
 9571
 9572        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9573        Some(
 9574            h_flex()
 9575                .min_w(min_width)
 9576                .max_w(max_width)
 9577                .flex_1()
 9578                .elevation_2(cx)
 9579                .border_color(cx.theme().colors().border)
 9580                .child(
 9581                    div()
 9582                        .flex_1()
 9583                        .py_1()
 9584                        .px_2()
 9585                        .overflow_hidden()
 9586                        .child(completion),
 9587                )
 9588                .when_some(accept_keystroke, |el, accept_keystroke| {
 9589                    if !accept_keystroke.modifiers().modified() {
 9590                        return el;
 9591                    }
 9592
 9593                    el.child(
 9594                        h_flex()
 9595                            .h_full()
 9596                            .border_l_1()
 9597                            .rounded_r_lg()
 9598                            .border_color(cx.theme().colors().border)
 9599                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9600                            .gap_1()
 9601                            .py_1()
 9602                            .px_2()
 9603                            .child(
 9604                                h_flex()
 9605                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9606                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 9607                                    .child(h_flex().children(ui::render_modifiers(
 9608                                        accept_keystroke.modifiers(),
 9609                                        PlatformStyle::platform(),
 9610                                        Some(if !has_completion {
 9611                                            Color::Muted
 9612                                        } else {
 9613                                            Color::Default
 9614                                        }),
 9615                                        None,
 9616                                        false,
 9617                                    ))),
 9618                            )
 9619                            .child(Label::new("Preview").into_any_element())
 9620                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 9621                    )
 9622                })
 9623                .into_any(),
 9624        )
 9625    }
 9626
 9627    fn render_edit_prediction_cursor_popover_preview(
 9628        &self,
 9629        completion: &EditPredictionState,
 9630        cursor_point: Point,
 9631        style: &EditorStyle,
 9632        cx: &mut Context<Editor>,
 9633    ) -> Option<Div> {
 9634        use text::ToPoint as _;
 9635
 9636        fn render_relative_row_jump(
 9637            prefix: impl Into<String>,
 9638            current_row: u32,
 9639            target_row: u32,
 9640        ) -> Div {
 9641            let (row_diff, arrow) = if target_row < current_row {
 9642                (current_row - target_row, IconName::ArrowUp)
 9643            } else {
 9644                (target_row - current_row, IconName::ArrowDown)
 9645            };
 9646
 9647            h_flex()
 9648                .child(
 9649                    Label::new(format!("{}{}", prefix.into(), row_diff))
 9650                        .color(Color::Muted)
 9651                        .size(LabelSize::Small),
 9652                )
 9653                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 9654        }
 9655
 9656        let supports_jump = self
 9657            .edit_prediction_provider
 9658            .as_ref()
 9659            .map(|provider| provider.provider.supports_jump_to_edit())
 9660            .unwrap_or(true);
 9661
 9662        match &completion.completion {
 9663            EditPrediction::MoveWithin {
 9664                target, snapshot, ..
 9665            } => {
 9666                if !supports_jump {
 9667                    return None;
 9668                }
 9669
 9670                Some(
 9671                    h_flex()
 9672                        .px_2()
 9673                        .gap_2()
 9674                        .flex_1()
 9675                        .child(
 9676                            if target.text_anchor.to_point(snapshot).row > cursor_point.row {
 9677                                Icon::new(IconName::ZedPredictDown)
 9678                            } else {
 9679                                Icon::new(IconName::ZedPredictUp)
 9680                            },
 9681                        )
 9682                        .child(Label::new("Jump to Edit")),
 9683                )
 9684            }
 9685            EditPrediction::MoveOutside { snapshot, .. } => {
 9686                let file_name = snapshot
 9687                    .file()
 9688                    .map(|file| file.file_name(cx))
 9689                    .unwrap_or("untitled");
 9690                Some(
 9691                    h_flex()
 9692                        .px_2()
 9693                        .gap_2()
 9694                        .flex_1()
 9695                        .child(Icon::new(IconName::ZedPredict))
 9696                        .child(Label::new(format!("Jump to {file_name}"))),
 9697                )
 9698            }
 9699            EditPrediction::Edit {
 9700                edits,
 9701                edit_preview,
 9702                snapshot,
 9703                display_mode: _,
 9704            } => {
 9705                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(snapshot).row;
 9706
 9707                let (highlighted_edits, has_more_lines) =
 9708                    if let Some(edit_preview) = edit_preview.as_ref() {
 9709                        crate::edit_prediction_edit_text(snapshot, edits, edit_preview, true, cx)
 9710                            .first_line_preview()
 9711                    } else {
 9712                        crate::edit_prediction_fallback_text(edits, cx).first_line_preview()
 9713                    };
 9714
 9715                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 9716                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 9717
 9718                let preview = h_flex()
 9719                    .gap_1()
 9720                    .min_w_16()
 9721                    .child(styled_text)
 9722                    .when(has_more_lines, |parent| parent.child(""));
 9723
 9724                let left = if supports_jump && first_edit_row != cursor_point.row {
 9725                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 9726                        .into_any_element()
 9727                } else {
 9728                    let icon_name =
 9729                        Editor::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9730                    Icon::new(icon_name).into_any_element()
 9731                };
 9732
 9733                Some(
 9734                    h_flex()
 9735                        .h_full()
 9736                        .flex_1()
 9737                        .gap_2()
 9738                        .pr_1()
 9739                        .overflow_x_hidden()
 9740                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9741                        .child(left)
 9742                        .child(preview),
 9743                )
 9744            }
 9745        }
 9746    }
 9747
 9748    pub fn render_context_menu(
 9749        &self,
 9750        style: &EditorStyle,
 9751        max_height_in_lines: u32,
 9752        window: &mut Window,
 9753        cx: &mut Context<Editor>,
 9754    ) -> Option<AnyElement> {
 9755        let menu = self.context_menu.borrow();
 9756        let menu = menu.as_ref()?;
 9757        if !menu.visible() {
 9758            return None;
 9759        };
 9760        Some(menu.render(style, max_height_in_lines, window, cx))
 9761    }
 9762
 9763    fn render_context_menu_aside(
 9764        &mut self,
 9765        max_size: Size<Pixels>,
 9766        window: &mut Window,
 9767        cx: &mut Context<Editor>,
 9768    ) -> Option<AnyElement> {
 9769        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 9770            if menu.visible() {
 9771                menu.render_aside(max_size, window, cx)
 9772            } else {
 9773                None
 9774            }
 9775        })
 9776    }
 9777
 9778    fn hide_context_menu(
 9779        &mut self,
 9780        window: &mut Window,
 9781        cx: &mut Context<Self>,
 9782    ) -> Option<CodeContextMenu> {
 9783        cx.notify();
 9784        self.completion_tasks.clear();
 9785        let context_menu = self.context_menu.borrow_mut().take();
 9786        self.stale_edit_prediction_in_menu.take();
 9787        self.update_visible_edit_prediction(window, cx);
 9788        if let Some(CodeContextMenu::Completions(_)) = &context_menu
 9789            && let Some(completion_provider) = &self.completion_provider
 9790        {
 9791            completion_provider.selection_changed(None, window, cx);
 9792        }
 9793        context_menu
 9794    }
 9795
 9796    fn show_snippet_choices(
 9797        &mut self,
 9798        choices: &Vec<String>,
 9799        selection: Range<Anchor>,
 9800        cx: &mut Context<Self>,
 9801    ) {
 9802        let Some((_, buffer, _)) = self
 9803            .buffer()
 9804            .read(cx)
 9805            .excerpt_containing(selection.start, cx)
 9806        else {
 9807            return;
 9808        };
 9809        let Some((_, end_buffer, _)) = self.buffer().read(cx).excerpt_containing(selection.end, cx)
 9810        else {
 9811            return;
 9812        };
 9813        if buffer != end_buffer {
 9814            log::error!("expected anchor range to have matching buffer IDs");
 9815            return;
 9816        }
 9817
 9818        let id = post_inc(&mut self.next_completion_id);
 9819        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 9820        *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 9821            CompletionsMenu::new_snippet_choices(
 9822                id,
 9823                true,
 9824                choices,
 9825                selection,
 9826                buffer,
 9827                snippet_sort_order,
 9828            ),
 9829        ));
 9830    }
 9831
 9832    pub fn insert_snippet(
 9833        &mut self,
 9834        insertion_ranges: &[Range<MultiBufferOffset>],
 9835        snippet: Snippet,
 9836        window: &mut Window,
 9837        cx: &mut Context<Self>,
 9838    ) -> Result<()> {
 9839        struct Tabstop<T> {
 9840            is_end_tabstop: bool,
 9841            ranges: Vec<Range<T>>,
 9842            choices: Option<Vec<String>>,
 9843        }
 9844
 9845        let tabstops = self.buffer.update(cx, |buffer, cx| {
 9846            let snippet_text: Arc<str> = snippet.text.clone().into();
 9847            let edits = insertion_ranges
 9848                .iter()
 9849                .cloned()
 9850                .map(|range| (range, snippet_text.clone()));
 9851            let autoindent_mode = AutoindentMode::Block {
 9852                original_indent_columns: Vec::new(),
 9853            };
 9854            buffer.edit(edits, Some(autoindent_mode), cx);
 9855
 9856            let snapshot = &*buffer.read(cx);
 9857            let snippet = &snippet;
 9858            snippet
 9859                .tabstops
 9860                .iter()
 9861                .map(|tabstop| {
 9862                    let is_end_tabstop = tabstop.ranges.first().is_some_and(|tabstop| {
 9863                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 9864                    });
 9865                    let mut tabstop_ranges = tabstop
 9866                        .ranges
 9867                        .iter()
 9868                        .flat_map(|tabstop_range| {
 9869                            let mut delta = 0_isize;
 9870                            insertion_ranges.iter().map(move |insertion_range| {
 9871                                let insertion_start = insertion_range.start + delta;
 9872                                delta += snippet.text.len() as isize
 9873                                    - (insertion_range.end - insertion_range.start) as isize;
 9874
 9875                                let start =
 9876                                    (insertion_start + tabstop_range.start).min(snapshot.len());
 9877                                let end = (insertion_start + tabstop_range.end).min(snapshot.len());
 9878                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 9879                            })
 9880                        })
 9881                        .collect::<Vec<_>>();
 9882                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 9883
 9884                    Tabstop {
 9885                        is_end_tabstop,
 9886                        ranges: tabstop_ranges,
 9887                        choices: tabstop.choices.clone(),
 9888                    }
 9889                })
 9890                .collect::<Vec<_>>()
 9891        });
 9892        if let Some(tabstop) = tabstops.first() {
 9893            self.change_selections(Default::default(), window, cx, |s| {
 9894                // Reverse order so that the first range is the newest created selection.
 9895                // Completions will use it and autoscroll will prioritize it.
 9896                s.select_ranges(tabstop.ranges.iter().rev().cloned());
 9897            });
 9898
 9899            if let Some(choices) = &tabstop.choices
 9900                && let Some(selection) = tabstop.ranges.first()
 9901            {
 9902                self.show_snippet_choices(choices, selection.clone(), cx)
 9903            }
 9904
 9905            // If we're already at the last tabstop and it's at the end of the snippet,
 9906            // we're done, we don't need to keep the state around.
 9907            if !tabstop.is_end_tabstop {
 9908                let choices = tabstops
 9909                    .iter()
 9910                    .map(|tabstop| tabstop.choices.clone())
 9911                    .collect();
 9912
 9913                let ranges = tabstops
 9914                    .into_iter()
 9915                    .map(|tabstop| tabstop.ranges)
 9916                    .collect::<Vec<_>>();
 9917
 9918                self.snippet_stack.push(SnippetState {
 9919                    active_index: 0,
 9920                    ranges,
 9921                    choices,
 9922                });
 9923            }
 9924
 9925            // Check whether the just-entered snippet ends with an auto-closable bracket.
 9926            if self.autoclose_regions.is_empty() {
 9927                let snapshot = self.buffer.read(cx).snapshot(cx);
 9928                for selection in &mut self.selections.all::<Point>(&self.display_snapshot(cx)) {
 9929                    let selection_head = selection.head();
 9930                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 9931                        continue;
 9932                    };
 9933
 9934                    let mut bracket_pair = None;
 9935                    let max_lookup_length = scope
 9936                        .brackets()
 9937                        .map(|(pair, _)| {
 9938                            pair.start
 9939                                .as_str()
 9940                                .chars()
 9941                                .count()
 9942                                .max(pair.end.as_str().chars().count())
 9943                        })
 9944                        .max();
 9945                    if let Some(max_lookup_length) = max_lookup_length {
 9946                        let next_text = snapshot
 9947                            .chars_at(selection_head)
 9948                            .take(max_lookup_length)
 9949                            .collect::<String>();
 9950                        let prev_text = snapshot
 9951                            .reversed_chars_at(selection_head)
 9952                            .take(max_lookup_length)
 9953                            .collect::<String>();
 9954
 9955                        for (pair, enabled) in scope.brackets() {
 9956                            if enabled
 9957                                && pair.close
 9958                                && prev_text.starts_with(pair.start.as_str())
 9959                                && next_text.starts_with(pair.end.as_str())
 9960                            {
 9961                                bracket_pair = Some(pair.clone());
 9962                                break;
 9963                            }
 9964                        }
 9965                    }
 9966
 9967                    if let Some(pair) = bracket_pair {
 9968                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 9969                        let autoclose_enabled =
 9970                            self.use_autoclose && snapshot_settings.use_autoclose;
 9971                        if autoclose_enabled {
 9972                            let start = snapshot.anchor_after(selection_head);
 9973                            let end = snapshot.anchor_after(selection_head);
 9974                            self.autoclose_regions.push(AutocloseRegion {
 9975                                selection_id: selection.id,
 9976                                range: start..end,
 9977                                pair,
 9978                            });
 9979                        }
 9980                    }
 9981                }
 9982            }
 9983        }
 9984        Ok(())
 9985    }
 9986
 9987    pub fn move_to_next_snippet_tabstop(
 9988        &mut self,
 9989        window: &mut Window,
 9990        cx: &mut Context<Self>,
 9991    ) -> bool {
 9992        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 9993    }
 9994
 9995    pub fn move_to_prev_snippet_tabstop(
 9996        &mut self,
 9997        window: &mut Window,
 9998        cx: &mut Context<Self>,
 9999    ) -> bool {
10000        self.move_to_snippet_tabstop(Bias::Left, window, cx)
10001    }
10002
10003    pub fn move_to_snippet_tabstop(
10004        &mut self,
10005        bias: Bias,
10006        window: &mut Window,
10007        cx: &mut Context<Self>,
10008    ) -> bool {
10009        if let Some(mut snippet) = self.snippet_stack.pop() {
10010            match bias {
10011                Bias::Left => {
10012                    if snippet.active_index > 0 {
10013                        snippet.active_index -= 1;
10014                    } else {
10015                        self.snippet_stack.push(snippet);
10016                        return false;
10017                    }
10018                }
10019                Bias::Right => {
10020                    if snippet.active_index + 1 < snippet.ranges.len() {
10021                        snippet.active_index += 1;
10022                    } else {
10023                        self.snippet_stack.push(snippet);
10024                        return false;
10025                    }
10026                }
10027            }
10028            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
10029                self.change_selections(Default::default(), window, cx, |s| {
10030                    // Reverse order so that the first range is the newest created selection.
10031                    // Completions will use it and autoscroll will prioritize it.
10032                    s.select_ranges(current_ranges.iter().rev().cloned())
10033                });
10034
10035                if let Some(choices) = &snippet.choices[snippet.active_index]
10036                    && let Some(selection) = current_ranges.first()
10037                {
10038                    self.show_snippet_choices(choices, selection.clone(), cx);
10039                }
10040
10041                // If snippet state is not at the last tabstop, push it back on the stack
10042                if snippet.active_index + 1 < snippet.ranges.len() {
10043                    self.snippet_stack.push(snippet);
10044                }
10045                return true;
10046            }
10047        }
10048
10049        false
10050    }
10051
10052    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
10053        self.transact(window, cx, |this, window, cx| {
10054            this.select_all(&SelectAll, window, cx);
10055            this.insert("", window, cx);
10056        });
10057    }
10058
10059    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
10060        if self.read_only(cx) {
10061            return;
10062        }
10063        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10064        self.transact(window, cx, |this, window, cx| {
10065            this.select_autoclose_pair(window, cx);
10066
10067            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
10068
10069            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
10070            if !this.linked_edit_ranges.is_empty() {
10071                let selections = this.selections.all::<MultiBufferPoint>(&display_map);
10072                let snapshot = this.buffer.read(cx).snapshot(cx);
10073
10074                for selection in selections.iter() {
10075                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
10076                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
10077                    if selection_start.buffer_id != selection_end.buffer_id {
10078                        continue;
10079                    }
10080                    if let Some(ranges) =
10081                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
10082                    {
10083                        for (buffer, entries) in ranges {
10084                            linked_ranges.entry(buffer).or_default().extend(entries);
10085                        }
10086                    }
10087                }
10088            }
10089
10090            let mut selections = this.selections.all::<MultiBufferPoint>(&display_map);
10091            for selection in &mut selections {
10092                if selection.is_empty() {
10093                    let old_head = selection.head();
10094                    let mut new_head =
10095                        movement::left(&display_map, old_head.to_display_point(&display_map))
10096                            .to_point(&display_map);
10097                    if let Some((buffer, line_buffer_range)) = display_map
10098                        .buffer_snapshot()
10099                        .buffer_line_for_row(MultiBufferRow(old_head.row))
10100                    {
10101                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
10102                        let indent_len = match indent_size.kind {
10103                            IndentKind::Space => {
10104                                buffer.settings_at(line_buffer_range.start, cx).tab_size
10105                            }
10106                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
10107                        };
10108                        if old_head.column <= indent_size.len && old_head.column > 0 {
10109                            let indent_len = indent_len.get();
10110                            new_head = cmp::min(
10111                                new_head,
10112                                MultiBufferPoint::new(
10113                                    old_head.row,
10114                                    ((old_head.column - 1) / indent_len) * indent_len,
10115                                ),
10116                            );
10117                        }
10118                    }
10119
10120                    selection.set_head(new_head, SelectionGoal::None);
10121                }
10122            }
10123
10124            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10125            this.insert("", window, cx);
10126            let empty_str: Arc<str> = Arc::from("");
10127            for (buffer, edits) in linked_ranges {
10128                let snapshot = buffer.read(cx).snapshot();
10129                use text::ToPoint as TP;
10130
10131                let edits = edits
10132                    .into_iter()
10133                    .map(|range| {
10134                        let end_point = TP::to_point(&range.end, &snapshot);
10135                        let mut start_point = TP::to_point(&range.start, &snapshot);
10136
10137                        if end_point == start_point {
10138                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
10139                                .saturating_sub(1);
10140                            start_point =
10141                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
10142                        };
10143
10144                        (start_point..end_point, empty_str.clone())
10145                    })
10146                    .sorted_by_key(|(range, _)| range.start)
10147                    .collect::<Vec<_>>();
10148                buffer.update(cx, |this, cx| {
10149                    this.edit(edits, None, cx);
10150                })
10151            }
10152            this.refresh_edit_prediction(true, false, window, cx);
10153            refresh_linked_ranges(this, window, cx);
10154        });
10155    }
10156
10157    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
10158        if self.read_only(cx) {
10159            return;
10160        }
10161        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10162        self.transact(window, cx, |this, window, cx| {
10163            this.change_selections(Default::default(), window, cx, |s| {
10164                s.move_with(|map, selection| {
10165                    if selection.is_empty() {
10166                        let cursor = movement::right(map, selection.head());
10167                        selection.end = cursor;
10168                        selection.reversed = true;
10169                        selection.goal = SelectionGoal::None;
10170                    }
10171                })
10172            });
10173            this.insert("", window, cx);
10174            this.refresh_edit_prediction(true, false, window, cx);
10175        });
10176    }
10177
10178    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
10179        if self.mode.is_single_line() {
10180            cx.propagate();
10181            return;
10182        }
10183
10184        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10185        if self.move_to_prev_snippet_tabstop(window, cx) {
10186            return;
10187        }
10188        self.outdent(&Outdent, window, cx);
10189    }
10190
10191    pub fn next_snippet_tabstop(
10192        &mut self,
10193        _: &NextSnippetTabstop,
10194        window: &mut Window,
10195        cx: &mut Context<Self>,
10196    ) {
10197        if self.mode.is_single_line() || self.snippet_stack.is_empty() {
10198            cx.propagate();
10199            return;
10200        }
10201
10202        if self.move_to_next_snippet_tabstop(window, cx) {
10203            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10204            return;
10205        }
10206        cx.propagate();
10207    }
10208
10209    pub fn previous_snippet_tabstop(
10210        &mut self,
10211        _: &PreviousSnippetTabstop,
10212        window: &mut Window,
10213        cx: &mut Context<Self>,
10214    ) {
10215        if self.mode.is_single_line() || self.snippet_stack.is_empty() {
10216            cx.propagate();
10217            return;
10218        }
10219
10220        if self.move_to_prev_snippet_tabstop(window, cx) {
10221            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10222            return;
10223        }
10224        cx.propagate();
10225    }
10226
10227    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
10228        if self.mode.is_single_line() {
10229            cx.propagate();
10230            return;
10231        }
10232
10233        if self.move_to_next_snippet_tabstop(window, cx) {
10234            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10235            return;
10236        }
10237        if self.read_only(cx) {
10238            return;
10239        }
10240        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10241        let mut selections = self.selections.all_adjusted(&self.display_snapshot(cx));
10242        let buffer = self.buffer.read(cx);
10243        let snapshot = buffer.snapshot(cx);
10244        let rows_iter = selections.iter().map(|s| s.head().row);
10245        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
10246
10247        let has_some_cursor_in_whitespace = selections
10248            .iter()
10249            .filter(|selection| selection.is_empty())
10250            .any(|selection| {
10251                let cursor = selection.head();
10252                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10253                cursor.column < current_indent.len
10254            });
10255
10256        let mut edits = Vec::new();
10257        let mut prev_edited_row = 0;
10258        let mut row_delta = 0;
10259        for selection in &mut selections {
10260            if selection.start.row != prev_edited_row {
10261                row_delta = 0;
10262            }
10263            prev_edited_row = selection.end.row;
10264
10265            // If the selection is non-empty, then increase the indentation of the selected lines.
10266            if !selection.is_empty() {
10267                row_delta =
10268                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10269                continue;
10270            }
10271
10272            let cursor = selection.head();
10273            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10274            if let Some(suggested_indent) =
10275                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
10276            {
10277                // Don't do anything if already at suggested indent
10278                // and there is any other cursor which is not
10279                if has_some_cursor_in_whitespace
10280                    && cursor.column == current_indent.len
10281                    && current_indent.len == suggested_indent.len
10282                {
10283                    continue;
10284                }
10285
10286                // Adjust line and move cursor to suggested indent
10287                // if cursor is not at suggested indent
10288                if cursor.column < suggested_indent.len
10289                    && cursor.column <= current_indent.len
10290                    && current_indent.len <= suggested_indent.len
10291                {
10292                    selection.start = Point::new(cursor.row, suggested_indent.len);
10293                    selection.end = selection.start;
10294                    if row_delta == 0 {
10295                        edits.extend(Buffer::edit_for_indent_size_adjustment(
10296                            cursor.row,
10297                            current_indent,
10298                            suggested_indent,
10299                        ));
10300                        row_delta = suggested_indent.len - current_indent.len;
10301                    }
10302                    continue;
10303                }
10304
10305                // If current indent is more than suggested indent
10306                // only move cursor to current indent and skip indent
10307                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
10308                    selection.start = Point::new(cursor.row, current_indent.len);
10309                    selection.end = selection.start;
10310                    continue;
10311                }
10312            }
10313
10314            // Otherwise, insert a hard or soft tab.
10315            let settings = buffer.language_settings_at(cursor, cx);
10316            let tab_size = if settings.hard_tabs {
10317                IndentSize::tab()
10318            } else {
10319                let tab_size = settings.tab_size.get();
10320                let indent_remainder = snapshot
10321                    .text_for_range(Point::new(cursor.row, 0)..cursor)
10322                    .flat_map(str::chars)
10323                    .fold(row_delta % tab_size, |counter: u32, c| {
10324                        if c == '\t' {
10325                            0
10326                        } else {
10327                            (counter + 1) % tab_size
10328                        }
10329                    });
10330
10331                let chars_to_next_tab_stop = tab_size - indent_remainder;
10332                IndentSize::spaces(chars_to_next_tab_stop)
10333            };
10334            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
10335            selection.end = selection.start;
10336            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
10337            row_delta += tab_size.len;
10338        }
10339
10340        self.transact(window, cx, |this, window, cx| {
10341            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10342            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10343            this.refresh_edit_prediction(true, false, window, cx);
10344        });
10345    }
10346
10347    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
10348        if self.read_only(cx) {
10349            return;
10350        }
10351        if self.mode.is_single_line() {
10352            cx.propagate();
10353            return;
10354        }
10355
10356        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10357        let mut selections = self.selections.all::<Point>(&self.display_snapshot(cx));
10358        let mut prev_edited_row = 0;
10359        let mut row_delta = 0;
10360        let mut edits = Vec::new();
10361        let buffer = self.buffer.read(cx);
10362        let snapshot = buffer.snapshot(cx);
10363        for selection in &mut selections {
10364            if selection.start.row != prev_edited_row {
10365                row_delta = 0;
10366            }
10367            prev_edited_row = selection.end.row;
10368
10369            row_delta =
10370                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10371        }
10372
10373        self.transact(window, cx, |this, window, cx| {
10374            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10375            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10376        });
10377    }
10378
10379    fn indent_selection(
10380        buffer: &MultiBuffer,
10381        snapshot: &MultiBufferSnapshot,
10382        selection: &mut Selection<Point>,
10383        edits: &mut Vec<(Range<Point>, String)>,
10384        delta_for_start_row: u32,
10385        cx: &App,
10386    ) -> u32 {
10387        let settings = buffer.language_settings_at(selection.start, cx);
10388        let tab_size = settings.tab_size.get();
10389        let indent_kind = if settings.hard_tabs {
10390            IndentKind::Tab
10391        } else {
10392            IndentKind::Space
10393        };
10394        let mut start_row = selection.start.row;
10395        let mut end_row = selection.end.row + 1;
10396
10397        // If a selection ends at the beginning of a line, don't indent
10398        // that last line.
10399        if selection.end.column == 0 && selection.end.row > selection.start.row {
10400            end_row -= 1;
10401        }
10402
10403        // Avoid re-indenting a row that has already been indented by a
10404        // previous selection, but still update this selection's column
10405        // to reflect that indentation.
10406        if delta_for_start_row > 0 {
10407            start_row += 1;
10408            selection.start.column += delta_for_start_row;
10409            if selection.end.row == selection.start.row {
10410                selection.end.column += delta_for_start_row;
10411            }
10412        }
10413
10414        let mut delta_for_end_row = 0;
10415        let has_multiple_rows = start_row + 1 != end_row;
10416        for row in start_row..end_row {
10417            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
10418            let indent_delta = match (current_indent.kind, indent_kind) {
10419                (IndentKind::Space, IndentKind::Space) => {
10420                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
10421                    IndentSize::spaces(columns_to_next_tab_stop)
10422                }
10423                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
10424                (_, IndentKind::Tab) => IndentSize::tab(),
10425            };
10426
10427            let start = if has_multiple_rows || current_indent.len < selection.start.column {
10428                0
10429            } else {
10430                selection.start.column
10431            };
10432            let row_start = Point::new(row, start);
10433            edits.push((
10434                row_start..row_start,
10435                indent_delta.chars().collect::<String>(),
10436            ));
10437
10438            // Update this selection's endpoints to reflect the indentation.
10439            if row == selection.start.row {
10440                selection.start.column += indent_delta.len;
10441            }
10442            if row == selection.end.row {
10443                selection.end.column += indent_delta.len;
10444                delta_for_end_row = indent_delta.len;
10445            }
10446        }
10447
10448        if selection.start.row == selection.end.row {
10449            delta_for_start_row + delta_for_end_row
10450        } else {
10451            delta_for_end_row
10452        }
10453    }
10454
10455    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
10456        if self.read_only(cx) {
10457            return;
10458        }
10459        if self.mode.is_single_line() {
10460            cx.propagate();
10461            return;
10462        }
10463
10464        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10465        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10466        let selections = self.selections.all::<Point>(&display_map);
10467        let mut deletion_ranges = Vec::new();
10468        let mut last_outdent = None;
10469        {
10470            let buffer = self.buffer.read(cx);
10471            let snapshot = buffer.snapshot(cx);
10472            for selection in &selections {
10473                let settings = buffer.language_settings_at(selection.start, cx);
10474                let tab_size = settings.tab_size.get();
10475                let mut rows = selection.spanned_rows(false, &display_map);
10476
10477                // Avoid re-outdenting a row that has already been outdented by a
10478                // previous selection.
10479                if let Some(last_row) = last_outdent
10480                    && last_row == rows.start
10481                {
10482                    rows.start = rows.start.next_row();
10483                }
10484                let has_multiple_rows = rows.len() > 1;
10485                for row in rows.iter_rows() {
10486                    let indent_size = snapshot.indent_size_for_line(row);
10487                    if indent_size.len > 0 {
10488                        let deletion_len = match indent_size.kind {
10489                            IndentKind::Space => {
10490                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
10491                                if columns_to_prev_tab_stop == 0 {
10492                                    tab_size
10493                                } else {
10494                                    columns_to_prev_tab_stop
10495                                }
10496                            }
10497                            IndentKind::Tab => 1,
10498                        };
10499                        let start = if has_multiple_rows
10500                            || deletion_len > selection.start.column
10501                            || indent_size.len < selection.start.column
10502                        {
10503                            0
10504                        } else {
10505                            selection.start.column - deletion_len
10506                        };
10507                        deletion_ranges.push(
10508                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
10509                        );
10510                        last_outdent = Some(row);
10511                    }
10512                }
10513            }
10514        }
10515
10516        self.transact(window, cx, |this, window, cx| {
10517            this.buffer.update(cx, |buffer, cx| {
10518                let empty_str: Arc<str> = Arc::default();
10519                buffer.edit(
10520                    deletion_ranges
10521                        .into_iter()
10522                        .map(|range| (range, empty_str.clone())),
10523                    None,
10524                    cx,
10525                );
10526            });
10527            let selections = this
10528                .selections
10529                .all::<MultiBufferOffset>(&this.display_snapshot(cx));
10530            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10531        });
10532    }
10533
10534    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
10535        if self.read_only(cx) {
10536            return;
10537        }
10538        if self.mode.is_single_line() {
10539            cx.propagate();
10540            return;
10541        }
10542
10543        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10544        let selections = self
10545            .selections
10546            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
10547            .into_iter()
10548            .map(|s| s.range());
10549
10550        self.transact(window, cx, |this, window, cx| {
10551            this.buffer.update(cx, |buffer, cx| {
10552                buffer.autoindent_ranges(selections, cx);
10553            });
10554            let selections = this
10555                .selections
10556                .all::<MultiBufferOffset>(&this.display_snapshot(cx));
10557            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10558        });
10559    }
10560
10561    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
10562        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10563        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10564        let selections = self.selections.all::<Point>(&display_map);
10565
10566        let mut new_cursors = Vec::new();
10567        let mut edit_ranges = Vec::new();
10568        let mut selections = selections.iter().peekable();
10569        while let Some(selection) = selections.next() {
10570            let mut rows = selection.spanned_rows(false, &display_map);
10571
10572            // Accumulate contiguous regions of rows that we want to delete.
10573            while let Some(next_selection) = selections.peek() {
10574                let next_rows = next_selection.spanned_rows(false, &display_map);
10575                if next_rows.start <= rows.end {
10576                    rows.end = next_rows.end;
10577                    selections.next().unwrap();
10578                } else {
10579                    break;
10580                }
10581            }
10582
10583            let buffer = display_map.buffer_snapshot();
10584            let mut edit_start = ToOffset::to_offset(&Point::new(rows.start.0, 0), buffer);
10585            let (edit_end, target_row) = if buffer.max_point().row >= rows.end.0 {
10586                // If there's a line after the range, delete the \n from the end of the row range
10587                (
10588                    ToOffset::to_offset(&Point::new(rows.end.0, 0), buffer),
10589                    rows.end,
10590                )
10591            } else {
10592                // If there isn't a line after the range, delete the \n from the line before the
10593                // start of the row range
10594                edit_start = edit_start.saturating_sub_usize(1);
10595                (buffer.len(), rows.start.previous_row())
10596            };
10597
10598            let text_layout_details = self.text_layout_details(window);
10599            let x = display_map.x_for_display_point(
10600                selection.head().to_display_point(&display_map),
10601                &text_layout_details,
10602            );
10603            let row = Point::new(target_row.0, 0)
10604                .to_display_point(&display_map)
10605                .row();
10606            let column = display_map.display_column_for_x(row, x, &text_layout_details);
10607
10608            new_cursors.push((
10609                selection.id,
10610                buffer.anchor_after(DisplayPoint::new(row, column).to_point(&display_map)),
10611                SelectionGoal::None,
10612            ));
10613            edit_ranges.push(edit_start..edit_end);
10614        }
10615
10616        self.transact(window, cx, |this, window, cx| {
10617            let buffer = this.buffer.update(cx, |buffer, cx| {
10618                let empty_str: Arc<str> = Arc::default();
10619                buffer.edit(
10620                    edit_ranges
10621                        .into_iter()
10622                        .map(|range| (range, empty_str.clone())),
10623                    None,
10624                    cx,
10625                );
10626                buffer.snapshot(cx)
10627            });
10628            let new_selections = new_cursors
10629                .into_iter()
10630                .map(|(id, cursor, goal)| {
10631                    let cursor = cursor.to_point(&buffer);
10632                    Selection {
10633                        id,
10634                        start: cursor,
10635                        end: cursor,
10636                        reversed: false,
10637                        goal,
10638                    }
10639                })
10640                .collect();
10641
10642            this.change_selections(Default::default(), window, cx, |s| {
10643                s.select(new_selections);
10644            });
10645        });
10646    }
10647
10648    pub fn join_lines_impl(
10649        &mut self,
10650        insert_whitespace: bool,
10651        window: &mut Window,
10652        cx: &mut Context<Self>,
10653    ) {
10654        if self.read_only(cx) {
10655            return;
10656        }
10657        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
10658        for selection in self.selections.all::<Point>(&self.display_snapshot(cx)) {
10659            let start = MultiBufferRow(selection.start.row);
10660            // Treat single line selections as if they include the next line. Otherwise this action
10661            // would do nothing for single line selections individual cursors.
10662            let end = if selection.start.row == selection.end.row {
10663                MultiBufferRow(selection.start.row + 1)
10664            } else {
10665                MultiBufferRow(selection.end.row)
10666            };
10667
10668            if let Some(last_row_range) = row_ranges.last_mut()
10669                && start <= last_row_range.end
10670            {
10671                last_row_range.end = end;
10672                continue;
10673            }
10674            row_ranges.push(start..end);
10675        }
10676
10677        let snapshot = self.buffer.read(cx).snapshot(cx);
10678        let mut cursor_positions = Vec::new();
10679        for row_range in &row_ranges {
10680            let anchor = snapshot.anchor_before(Point::new(
10681                row_range.end.previous_row().0,
10682                snapshot.line_len(row_range.end.previous_row()),
10683            ));
10684            cursor_positions.push(anchor..anchor);
10685        }
10686
10687        self.transact(window, cx, |this, window, cx| {
10688            for row_range in row_ranges.into_iter().rev() {
10689                for row in row_range.iter_rows().rev() {
10690                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
10691                    let next_line_row = row.next_row();
10692                    let indent = snapshot.indent_size_for_line(next_line_row);
10693                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
10694
10695                    let replace =
10696                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
10697                            " "
10698                        } else {
10699                            ""
10700                        };
10701
10702                    this.buffer.update(cx, |buffer, cx| {
10703                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
10704                    });
10705                }
10706            }
10707
10708            this.change_selections(Default::default(), window, cx, |s| {
10709                s.select_anchor_ranges(cursor_positions)
10710            });
10711        });
10712    }
10713
10714    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
10715        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10716        self.join_lines_impl(true, window, cx);
10717    }
10718
10719    pub fn sort_lines_case_sensitive(
10720        &mut self,
10721        _: &SortLinesCaseSensitive,
10722        window: &mut Window,
10723        cx: &mut Context<Self>,
10724    ) {
10725        self.manipulate_immutable_lines(window, cx, |lines| lines.sort())
10726    }
10727
10728    pub fn sort_lines_by_length(
10729        &mut self,
10730        _: &SortLinesByLength,
10731        window: &mut Window,
10732        cx: &mut Context<Self>,
10733    ) {
10734        self.manipulate_immutable_lines(window, cx, |lines| {
10735            lines.sort_by_key(|&line| line.chars().count())
10736        })
10737    }
10738
10739    pub fn sort_lines_case_insensitive(
10740        &mut self,
10741        _: &SortLinesCaseInsensitive,
10742        window: &mut Window,
10743        cx: &mut Context<Self>,
10744    ) {
10745        self.manipulate_immutable_lines(window, cx, |lines| {
10746            lines.sort_by_key(|line| line.to_lowercase())
10747        })
10748    }
10749
10750    pub fn unique_lines_case_insensitive(
10751        &mut self,
10752        _: &UniqueLinesCaseInsensitive,
10753        window: &mut Window,
10754        cx: &mut Context<Self>,
10755    ) {
10756        self.manipulate_immutable_lines(window, cx, |lines| {
10757            let mut seen = HashSet::default();
10758            lines.retain(|line| seen.insert(line.to_lowercase()));
10759        })
10760    }
10761
10762    pub fn unique_lines_case_sensitive(
10763        &mut self,
10764        _: &UniqueLinesCaseSensitive,
10765        window: &mut Window,
10766        cx: &mut Context<Self>,
10767    ) {
10768        self.manipulate_immutable_lines(window, cx, |lines| {
10769            let mut seen = HashSet::default();
10770            lines.retain(|line| seen.insert(*line));
10771        })
10772    }
10773
10774    fn enable_wrap_selections_in_tag(&self, cx: &App) -> bool {
10775        let snapshot = self.buffer.read(cx).snapshot(cx);
10776        for selection in self.selections.disjoint_anchors_arc().iter() {
10777            if snapshot
10778                .language_at(selection.start)
10779                .and_then(|lang| lang.config().wrap_characters.as_ref())
10780                .is_some()
10781            {
10782                return true;
10783            }
10784        }
10785        false
10786    }
10787
10788    fn wrap_selections_in_tag(
10789        &mut self,
10790        _: &WrapSelectionsInTag,
10791        window: &mut Window,
10792        cx: &mut Context<Self>,
10793    ) {
10794        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10795
10796        let snapshot = self.buffer.read(cx).snapshot(cx);
10797
10798        let mut edits = Vec::new();
10799        let mut boundaries = Vec::new();
10800
10801        for selection in self
10802            .selections
10803            .all_adjusted(&self.display_snapshot(cx))
10804            .iter()
10805        {
10806            let Some(wrap_config) = snapshot
10807                .language_at(selection.start)
10808                .and_then(|lang| lang.config().wrap_characters.clone())
10809            else {
10810                continue;
10811            };
10812
10813            let open_tag = format!("{}{}", wrap_config.start_prefix, wrap_config.start_suffix);
10814            let close_tag = format!("{}{}", wrap_config.end_prefix, wrap_config.end_suffix);
10815
10816            let start_before = snapshot.anchor_before(selection.start);
10817            let end_after = snapshot.anchor_after(selection.end);
10818
10819            edits.push((start_before..start_before, open_tag));
10820            edits.push((end_after..end_after, close_tag));
10821
10822            boundaries.push((
10823                start_before,
10824                end_after,
10825                wrap_config.start_prefix.len(),
10826                wrap_config.end_suffix.len(),
10827            ));
10828        }
10829
10830        if edits.is_empty() {
10831            return;
10832        }
10833
10834        self.transact(window, cx, |this, window, cx| {
10835            let buffer = this.buffer.update(cx, |buffer, cx| {
10836                buffer.edit(edits, None, cx);
10837                buffer.snapshot(cx)
10838            });
10839
10840            let mut new_selections = Vec::with_capacity(boundaries.len() * 2);
10841            for (start_before, end_after, start_prefix_len, end_suffix_len) in
10842                boundaries.into_iter()
10843            {
10844                let open_offset = start_before.to_offset(&buffer) + start_prefix_len;
10845                let close_offset = end_after
10846                    .to_offset(&buffer)
10847                    .saturating_sub_usize(end_suffix_len);
10848                new_selections.push(open_offset..open_offset);
10849                new_selections.push(close_offset..close_offset);
10850            }
10851
10852            this.change_selections(Default::default(), window, cx, |s| {
10853                s.select_ranges(new_selections);
10854            });
10855
10856            this.request_autoscroll(Autoscroll::fit(), cx);
10857        });
10858    }
10859
10860    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
10861        let Some(project) = self.project.clone() else {
10862            return;
10863        };
10864        self.reload(project, window, cx)
10865            .detach_and_notify_err(window, cx);
10866    }
10867
10868    pub fn restore_file(
10869        &mut self,
10870        _: &::git::RestoreFile,
10871        window: &mut Window,
10872        cx: &mut Context<Self>,
10873    ) {
10874        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10875        let mut buffer_ids = HashSet::default();
10876        let snapshot = self.buffer().read(cx).snapshot(cx);
10877        for selection in self
10878            .selections
10879            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
10880        {
10881            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
10882        }
10883
10884        let buffer = self.buffer().read(cx);
10885        let ranges = buffer_ids
10886            .into_iter()
10887            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
10888            .collect::<Vec<_>>();
10889
10890        self.restore_hunks_in_ranges(ranges, window, cx);
10891    }
10892
10893    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
10894        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10895        let selections = self
10896            .selections
10897            .all(&self.display_snapshot(cx))
10898            .into_iter()
10899            .map(|s| s.range())
10900            .collect();
10901        self.restore_hunks_in_ranges(selections, window, cx);
10902    }
10903
10904    pub fn restore_hunks_in_ranges(
10905        &mut self,
10906        ranges: Vec<Range<Point>>,
10907        window: &mut Window,
10908        cx: &mut Context<Editor>,
10909    ) {
10910        let mut revert_changes = HashMap::default();
10911        let chunk_by = self
10912            .snapshot(window, cx)
10913            .hunks_for_ranges(ranges)
10914            .into_iter()
10915            .chunk_by(|hunk| hunk.buffer_id);
10916        for (buffer_id, hunks) in &chunk_by {
10917            let hunks = hunks.collect::<Vec<_>>();
10918            for hunk in &hunks {
10919                self.prepare_restore_change(&mut revert_changes, hunk, cx);
10920            }
10921            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
10922        }
10923        drop(chunk_by);
10924        if !revert_changes.is_empty() {
10925            self.transact(window, cx, |editor, window, cx| {
10926                editor.restore(revert_changes, window, cx);
10927            });
10928        }
10929    }
10930
10931    pub fn status_for_buffer_id(&self, buffer_id: BufferId, cx: &App) -> Option<FileStatus> {
10932        if let Some(status) = self
10933            .addons
10934            .iter()
10935            .find_map(|(_, addon)| addon.override_status_for_buffer_id(buffer_id, cx))
10936        {
10937            return Some(status);
10938        }
10939        self.project
10940            .as_ref()?
10941            .read(cx)
10942            .status_for_buffer_id(buffer_id, cx)
10943    }
10944
10945    pub fn open_active_item_in_terminal(
10946        &mut self,
10947        _: &OpenInTerminal,
10948        window: &mut Window,
10949        cx: &mut Context<Self>,
10950    ) {
10951        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
10952            let project_path = buffer.read(cx).project_path(cx)?;
10953            let project = self.project()?.read(cx);
10954            let entry = project.entry_for_path(&project_path, cx)?;
10955            let parent = match &entry.canonical_path {
10956                Some(canonical_path) => canonical_path.to_path_buf(),
10957                None => project.absolute_path(&project_path, cx)?,
10958            }
10959            .parent()?
10960            .to_path_buf();
10961            Some(parent)
10962        }) {
10963            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
10964        }
10965    }
10966
10967    fn set_breakpoint_context_menu(
10968        &mut self,
10969        display_row: DisplayRow,
10970        position: Option<Anchor>,
10971        clicked_point: gpui::Point<Pixels>,
10972        window: &mut Window,
10973        cx: &mut Context<Self>,
10974    ) {
10975        let source = self
10976            .buffer
10977            .read(cx)
10978            .snapshot(cx)
10979            .anchor_before(Point::new(display_row.0, 0u32));
10980
10981        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
10982
10983        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
10984            self,
10985            source,
10986            clicked_point,
10987            context_menu,
10988            window,
10989            cx,
10990        );
10991    }
10992
10993    fn add_edit_breakpoint_block(
10994        &mut self,
10995        anchor: Anchor,
10996        breakpoint: &Breakpoint,
10997        edit_action: BreakpointPromptEditAction,
10998        window: &mut Window,
10999        cx: &mut Context<Self>,
11000    ) {
11001        let weak_editor = cx.weak_entity();
11002        let bp_prompt = cx.new(|cx| {
11003            BreakpointPromptEditor::new(
11004                weak_editor,
11005                anchor,
11006                breakpoint.clone(),
11007                edit_action,
11008                window,
11009                cx,
11010            )
11011        });
11012
11013        let height = bp_prompt.update(cx, |this, cx| {
11014            this.prompt
11015                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
11016        });
11017        let cloned_prompt = bp_prompt.clone();
11018        let blocks = vec![BlockProperties {
11019            style: BlockStyle::Sticky,
11020            placement: BlockPlacement::Above(anchor),
11021            height: Some(height),
11022            render: Arc::new(move |cx| {
11023                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
11024                cloned_prompt.clone().into_any_element()
11025            }),
11026            priority: 0,
11027        }];
11028
11029        let focus_handle = bp_prompt.focus_handle(cx);
11030        window.focus(&focus_handle);
11031
11032        let block_ids = self.insert_blocks(blocks, None, cx);
11033        bp_prompt.update(cx, |prompt, _| {
11034            prompt.add_block_ids(block_ids);
11035        });
11036    }
11037
11038    pub(crate) fn breakpoint_at_row(
11039        &self,
11040        row: u32,
11041        window: &mut Window,
11042        cx: &mut Context<Self>,
11043    ) -> Option<(Anchor, Breakpoint)> {
11044        let snapshot = self.snapshot(window, cx);
11045        let breakpoint_position = snapshot.buffer_snapshot().anchor_before(Point::new(row, 0));
11046
11047        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
11048    }
11049
11050    pub(crate) fn breakpoint_at_anchor(
11051        &self,
11052        breakpoint_position: Anchor,
11053        snapshot: &EditorSnapshot,
11054        cx: &mut Context<Self>,
11055    ) -> Option<(Anchor, Breakpoint)> {
11056        let buffer = self
11057            .buffer
11058            .read(cx)
11059            .buffer_for_anchor(breakpoint_position, cx)?;
11060
11061        let enclosing_excerpt = breakpoint_position.excerpt_id;
11062        let buffer_snapshot = buffer.read(cx).snapshot();
11063
11064        let row = buffer_snapshot
11065            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
11066            .row;
11067
11068        let line_len = snapshot.buffer_snapshot().line_len(MultiBufferRow(row));
11069        let anchor_end = snapshot
11070            .buffer_snapshot()
11071            .anchor_after(Point::new(row, line_len));
11072
11073        self.breakpoint_store
11074            .as_ref()?
11075            .read_with(cx, |breakpoint_store, cx| {
11076                breakpoint_store
11077                    .breakpoints(
11078                        &buffer,
11079                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
11080                        &buffer_snapshot,
11081                        cx,
11082                    )
11083                    .next()
11084                    .and_then(|(bp, _)| {
11085                        let breakpoint_row = buffer_snapshot
11086                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
11087                            .row;
11088
11089                        if breakpoint_row == row {
11090                            snapshot
11091                                .buffer_snapshot()
11092                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
11093                                .map(|position| (position, bp.bp.clone()))
11094                        } else {
11095                            None
11096                        }
11097                    })
11098            })
11099    }
11100
11101    pub fn edit_log_breakpoint(
11102        &mut self,
11103        _: &EditLogBreakpoint,
11104        window: &mut Window,
11105        cx: &mut Context<Self>,
11106    ) {
11107        if self.breakpoint_store.is_none() {
11108            return;
11109        }
11110
11111        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11112            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
11113                message: None,
11114                state: BreakpointState::Enabled,
11115                condition: None,
11116                hit_condition: None,
11117            });
11118
11119            self.add_edit_breakpoint_block(
11120                anchor,
11121                &breakpoint,
11122                BreakpointPromptEditAction::Log,
11123                window,
11124                cx,
11125            );
11126        }
11127    }
11128
11129    fn breakpoints_at_cursors(
11130        &self,
11131        window: &mut Window,
11132        cx: &mut Context<Self>,
11133    ) -> Vec<(Anchor, Option<Breakpoint>)> {
11134        let snapshot = self.snapshot(window, cx);
11135        let cursors = self
11136            .selections
11137            .disjoint_anchors_arc()
11138            .iter()
11139            .map(|selection| {
11140                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot());
11141
11142                let breakpoint_position = self
11143                    .breakpoint_at_row(cursor_position.row, window, cx)
11144                    .map(|bp| bp.0)
11145                    .unwrap_or_else(|| {
11146                        snapshot
11147                            .display_snapshot
11148                            .buffer_snapshot()
11149                            .anchor_after(Point::new(cursor_position.row, 0))
11150                    });
11151
11152                let breakpoint = self
11153                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
11154                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
11155
11156                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
11157            })
11158            // 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.
11159            .collect::<HashMap<Anchor, _>>();
11160
11161        cursors.into_iter().collect()
11162    }
11163
11164    pub fn enable_breakpoint(
11165        &mut self,
11166        _: &crate::actions::EnableBreakpoint,
11167        window: &mut Window,
11168        cx: &mut Context<Self>,
11169    ) {
11170        if self.breakpoint_store.is_none() {
11171            return;
11172        }
11173
11174        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11175            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
11176                continue;
11177            };
11178            self.edit_breakpoint_at_anchor(
11179                anchor,
11180                breakpoint,
11181                BreakpointEditAction::InvertState,
11182                cx,
11183            );
11184        }
11185    }
11186
11187    pub fn disable_breakpoint(
11188        &mut self,
11189        _: &crate::actions::DisableBreakpoint,
11190        window: &mut Window,
11191        cx: &mut Context<Self>,
11192    ) {
11193        if self.breakpoint_store.is_none() {
11194            return;
11195        }
11196
11197        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11198            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
11199                continue;
11200            };
11201            self.edit_breakpoint_at_anchor(
11202                anchor,
11203                breakpoint,
11204                BreakpointEditAction::InvertState,
11205                cx,
11206            );
11207        }
11208    }
11209
11210    pub fn toggle_breakpoint(
11211        &mut self,
11212        _: &crate::actions::ToggleBreakpoint,
11213        window: &mut Window,
11214        cx: &mut Context<Self>,
11215    ) {
11216        if self.breakpoint_store.is_none() {
11217            return;
11218        }
11219
11220        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11221            if let Some(breakpoint) = breakpoint {
11222                self.edit_breakpoint_at_anchor(
11223                    anchor,
11224                    breakpoint,
11225                    BreakpointEditAction::Toggle,
11226                    cx,
11227                );
11228            } else {
11229                self.edit_breakpoint_at_anchor(
11230                    anchor,
11231                    Breakpoint::new_standard(),
11232                    BreakpointEditAction::Toggle,
11233                    cx,
11234                );
11235            }
11236        }
11237    }
11238
11239    pub fn edit_breakpoint_at_anchor(
11240        &mut self,
11241        breakpoint_position: Anchor,
11242        breakpoint: Breakpoint,
11243        edit_action: BreakpointEditAction,
11244        cx: &mut Context<Self>,
11245    ) {
11246        let Some(breakpoint_store) = &self.breakpoint_store else {
11247            return;
11248        };
11249
11250        let Some(buffer) = self
11251            .buffer
11252            .read(cx)
11253            .buffer_for_anchor(breakpoint_position, cx)
11254        else {
11255            return;
11256        };
11257
11258        breakpoint_store.update(cx, |breakpoint_store, cx| {
11259            breakpoint_store.toggle_breakpoint(
11260                buffer,
11261                BreakpointWithPosition {
11262                    position: breakpoint_position.text_anchor,
11263                    bp: breakpoint,
11264                },
11265                edit_action,
11266                cx,
11267            );
11268        });
11269
11270        cx.notify();
11271    }
11272
11273    #[cfg(any(test, feature = "test-support"))]
11274    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
11275        self.breakpoint_store.clone()
11276    }
11277
11278    pub fn prepare_restore_change(
11279        &self,
11280        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
11281        hunk: &MultiBufferDiffHunk,
11282        cx: &mut App,
11283    ) -> Option<()> {
11284        if hunk.is_created_file() {
11285            return None;
11286        }
11287        let buffer = self.buffer.read(cx);
11288        let diff = buffer.diff_for(hunk.buffer_id)?;
11289        let buffer = buffer.buffer(hunk.buffer_id)?;
11290        let buffer = buffer.read(cx);
11291        let original_text = diff
11292            .read(cx)
11293            .base_text()
11294            .as_rope()
11295            .slice(hunk.diff_base_byte_range.start.0..hunk.diff_base_byte_range.end.0);
11296        let buffer_snapshot = buffer.snapshot();
11297        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
11298        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
11299            probe
11300                .0
11301                .start
11302                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
11303                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
11304        }) {
11305            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
11306            Some(())
11307        } else {
11308            None
11309        }
11310    }
11311
11312    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
11313        self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())
11314    }
11315
11316    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
11317        self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut rand::rng()))
11318    }
11319
11320    fn manipulate_lines<M>(
11321        &mut self,
11322        window: &mut Window,
11323        cx: &mut Context<Self>,
11324        mut manipulate: M,
11325    ) where
11326        M: FnMut(&str) -> LineManipulationResult,
11327    {
11328        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11329
11330        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11331        let buffer = self.buffer.read(cx).snapshot(cx);
11332
11333        let mut edits = Vec::new();
11334
11335        let selections = self.selections.all::<Point>(&display_map);
11336        let mut selections = selections.iter().peekable();
11337        let mut contiguous_row_selections = Vec::new();
11338        let mut new_selections = Vec::new();
11339        let mut added_lines = 0;
11340        let mut removed_lines = 0;
11341
11342        while let Some(selection) = selections.next() {
11343            let (start_row, end_row) = consume_contiguous_rows(
11344                &mut contiguous_row_selections,
11345                selection,
11346                &display_map,
11347                &mut selections,
11348            );
11349
11350            let start_point = Point::new(start_row.0, 0);
11351            let end_point = Point::new(
11352                end_row.previous_row().0,
11353                buffer.line_len(end_row.previous_row()),
11354            );
11355            let text = buffer
11356                .text_for_range(start_point..end_point)
11357                .collect::<String>();
11358
11359            let LineManipulationResult {
11360                new_text,
11361                line_count_before,
11362                line_count_after,
11363            } = manipulate(&text);
11364
11365            edits.push((start_point..end_point, new_text));
11366
11367            // Selections must change based on added and removed line count
11368            let start_row =
11369                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
11370            let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);
11371            new_selections.push(Selection {
11372                id: selection.id,
11373                start: start_row,
11374                end: end_row,
11375                goal: SelectionGoal::None,
11376                reversed: selection.reversed,
11377            });
11378
11379            if line_count_after > line_count_before {
11380                added_lines += line_count_after - line_count_before;
11381            } else if line_count_before > line_count_after {
11382                removed_lines += line_count_before - line_count_after;
11383            }
11384        }
11385
11386        self.transact(window, cx, |this, window, cx| {
11387            let buffer = this.buffer.update(cx, |buffer, cx| {
11388                buffer.edit(edits, None, cx);
11389                buffer.snapshot(cx)
11390            });
11391
11392            // Recalculate offsets on newly edited buffer
11393            let new_selections = new_selections
11394                .iter()
11395                .map(|s| {
11396                    let start_point = Point::new(s.start.0, 0);
11397                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
11398                    Selection {
11399                        id: s.id,
11400                        start: buffer.point_to_offset(start_point),
11401                        end: buffer.point_to_offset(end_point),
11402                        goal: s.goal,
11403                        reversed: s.reversed,
11404                    }
11405                })
11406                .collect();
11407
11408            this.change_selections(Default::default(), window, cx, |s| {
11409                s.select(new_selections);
11410            });
11411
11412            this.request_autoscroll(Autoscroll::fit(), cx);
11413        });
11414    }
11415
11416    fn manipulate_immutable_lines<Fn>(
11417        &mut self,
11418        window: &mut Window,
11419        cx: &mut Context<Self>,
11420        mut callback: Fn,
11421    ) where
11422        Fn: FnMut(&mut Vec<&str>),
11423    {
11424        self.manipulate_lines(window, cx, |text| {
11425            let mut lines: Vec<&str> = text.split('\n').collect();
11426            let line_count_before = lines.len();
11427
11428            callback(&mut lines);
11429
11430            LineManipulationResult {
11431                new_text: lines.join("\n"),
11432                line_count_before,
11433                line_count_after: lines.len(),
11434            }
11435        });
11436    }
11437
11438    fn manipulate_mutable_lines<Fn>(
11439        &mut self,
11440        window: &mut Window,
11441        cx: &mut Context<Self>,
11442        mut callback: Fn,
11443    ) where
11444        Fn: FnMut(&mut Vec<Cow<'_, str>>),
11445    {
11446        self.manipulate_lines(window, cx, |text| {
11447            let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
11448            let line_count_before = lines.len();
11449
11450            callback(&mut lines);
11451
11452            LineManipulationResult {
11453                new_text: lines.join("\n"),
11454                line_count_before,
11455                line_count_after: lines.len(),
11456            }
11457        });
11458    }
11459
11460    pub fn convert_indentation_to_spaces(
11461        &mut self,
11462        _: &ConvertIndentationToSpaces,
11463        window: &mut Window,
11464        cx: &mut Context<Self>,
11465    ) {
11466        let settings = self.buffer.read(cx).language_settings(cx);
11467        let tab_size = settings.tab_size.get() as usize;
11468
11469        self.manipulate_mutable_lines(window, cx, |lines| {
11470            // Allocates a reasonably sized scratch buffer once for the whole loop
11471            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11472            // Avoids recomputing spaces that could be inserted many times
11473            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11474                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11475                .collect();
11476
11477            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11478                let mut chars = line.as_ref().chars();
11479                let mut col = 0;
11480                let mut changed = false;
11481
11482                for ch in chars.by_ref() {
11483                    match ch {
11484                        ' ' => {
11485                            reindented_line.push(' ');
11486                            col += 1;
11487                        }
11488                        '\t' => {
11489                            // \t are converted to spaces depending on the current column
11490                            let spaces_len = tab_size - (col % tab_size);
11491                            reindented_line.extend(&space_cache[spaces_len - 1]);
11492                            col += spaces_len;
11493                            changed = true;
11494                        }
11495                        _ => {
11496                            // If we dont append before break, the character is consumed
11497                            reindented_line.push(ch);
11498                            break;
11499                        }
11500                    }
11501                }
11502
11503                if !changed {
11504                    reindented_line.clear();
11505                    continue;
11506                }
11507                // Append the rest of the line and replace old reference with new one
11508                reindented_line.extend(chars);
11509                *line = Cow::Owned(reindented_line.clone());
11510                reindented_line.clear();
11511            }
11512        });
11513    }
11514
11515    pub fn convert_indentation_to_tabs(
11516        &mut self,
11517        _: &ConvertIndentationToTabs,
11518        window: &mut Window,
11519        cx: &mut Context<Self>,
11520    ) {
11521        let settings = self.buffer.read(cx).language_settings(cx);
11522        let tab_size = settings.tab_size.get() as usize;
11523
11524        self.manipulate_mutable_lines(window, cx, |lines| {
11525            // Allocates a reasonably sized buffer once for the whole loop
11526            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11527            // Avoids recomputing spaces that could be inserted many times
11528            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11529                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11530                .collect();
11531
11532            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11533                let mut chars = line.chars();
11534                let mut spaces_count = 0;
11535                let mut first_non_indent_char = None;
11536                let mut changed = false;
11537
11538                for ch in chars.by_ref() {
11539                    match ch {
11540                        ' ' => {
11541                            // Keep track of spaces. Append \t when we reach tab_size
11542                            spaces_count += 1;
11543                            changed = true;
11544                            if spaces_count == tab_size {
11545                                reindented_line.push('\t');
11546                                spaces_count = 0;
11547                            }
11548                        }
11549                        '\t' => {
11550                            reindented_line.push('\t');
11551                            spaces_count = 0;
11552                        }
11553                        _ => {
11554                            // Dont append it yet, we might have remaining spaces
11555                            first_non_indent_char = Some(ch);
11556                            break;
11557                        }
11558                    }
11559                }
11560
11561                if !changed {
11562                    reindented_line.clear();
11563                    continue;
11564                }
11565                // Remaining spaces that didn't make a full tab stop
11566                if spaces_count > 0 {
11567                    reindented_line.extend(&space_cache[spaces_count - 1]);
11568                }
11569                // If we consume an extra character that was not indentation, add it back
11570                if let Some(extra_char) = first_non_indent_char {
11571                    reindented_line.push(extra_char);
11572                }
11573                // Append the rest of the line and replace old reference with new one
11574                reindented_line.extend(chars);
11575                *line = Cow::Owned(reindented_line.clone());
11576                reindented_line.clear();
11577            }
11578        });
11579    }
11580
11581    pub fn convert_to_upper_case(
11582        &mut self,
11583        _: &ConvertToUpperCase,
11584        window: &mut Window,
11585        cx: &mut Context<Self>,
11586    ) {
11587        self.manipulate_text(window, cx, |text| text.to_uppercase())
11588    }
11589
11590    pub fn convert_to_lower_case(
11591        &mut self,
11592        _: &ConvertToLowerCase,
11593        window: &mut Window,
11594        cx: &mut Context<Self>,
11595    ) {
11596        self.manipulate_text(window, cx, |text| text.to_lowercase())
11597    }
11598
11599    pub fn convert_to_title_case(
11600        &mut self,
11601        _: &ConvertToTitleCase,
11602        window: &mut Window,
11603        cx: &mut Context<Self>,
11604    ) {
11605        self.manipulate_text(window, cx, |text| {
11606            text.split('\n')
11607                .map(|line| line.to_case(Case::Title))
11608                .join("\n")
11609        })
11610    }
11611
11612    pub fn convert_to_snake_case(
11613        &mut self,
11614        _: &ConvertToSnakeCase,
11615        window: &mut Window,
11616        cx: &mut Context<Self>,
11617    ) {
11618        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
11619    }
11620
11621    pub fn convert_to_kebab_case(
11622        &mut self,
11623        _: &ConvertToKebabCase,
11624        window: &mut Window,
11625        cx: &mut Context<Self>,
11626    ) {
11627        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
11628    }
11629
11630    pub fn convert_to_upper_camel_case(
11631        &mut self,
11632        _: &ConvertToUpperCamelCase,
11633        window: &mut Window,
11634        cx: &mut Context<Self>,
11635    ) {
11636        self.manipulate_text(window, cx, |text| {
11637            text.split('\n')
11638                .map(|line| line.to_case(Case::UpperCamel))
11639                .join("\n")
11640        })
11641    }
11642
11643    pub fn convert_to_lower_camel_case(
11644        &mut self,
11645        _: &ConvertToLowerCamelCase,
11646        window: &mut Window,
11647        cx: &mut Context<Self>,
11648    ) {
11649        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
11650    }
11651
11652    pub fn convert_to_opposite_case(
11653        &mut self,
11654        _: &ConvertToOppositeCase,
11655        window: &mut Window,
11656        cx: &mut Context<Self>,
11657    ) {
11658        self.manipulate_text(window, cx, |text| {
11659            text.chars()
11660                .fold(String::with_capacity(text.len()), |mut t, c| {
11661                    if c.is_uppercase() {
11662                        t.extend(c.to_lowercase());
11663                    } else {
11664                        t.extend(c.to_uppercase());
11665                    }
11666                    t
11667                })
11668        })
11669    }
11670
11671    pub fn convert_to_sentence_case(
11672        &mut self,
11673        _: &ConvertToSentenceCase,
11674        window: &mut Window,
11675        cx: &mut Context<Self>,
11676    ) {
11677        self.manipulate_text(window, cx, |text| text.to_case(Case::Sentence))
11678    }
11679
11680    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
11681        self.manipulate_text(window, cx, |text| {
11682            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
11683            if has_upper_case_characters {
11684                text.to_lowercase()
11685            } else {
11686                text.to_uppercase()
11687            }
11688        })
11689    }
11690
11691    pub fn convert_to_rot13(
11692        &mut self,
11693        _: &ConvertToRot13,
11694        window: &mut Window,
11695        cx: &mut Context<Self>,
11696    ) {
11697        self.manipulate_text(window, cx, |text| {
11698            text.chars()
11699                .map(|c| match c {
11700                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
11701                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
11702                    _ => c,
11703                })
11704                .collect()
11705        })
11706    }
11707
11708    pub fn convert_to_rot47(
11709        &mut self,
11710        _: &ConvertToRot47,
11711        window: &mut Window,
11712        cx: &mut Context<Self>,
11713    ) {
11714        self.manipulate_text(window, cx, |text| {
11715            text.chars()
11716                .map(|c| {
11717                    let code_point = c as u32;
11718                    if code_point >= 33 && code_point <= 126 {
11719                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
11720                    }
11721                    c
11722                })
11723                .collect()
11724        })
11725    }
11726
11727    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
11728    where
11729        Fn: FnMut(&str) -> String,
11730    {
11731        let buffer = self.buffer.read(cx).snapshot(cx);
11732
11733        let mut new_selections = Vec::new();
11734        let mut edits = Vec::new();
11735        let mut selection_adjustment = 0isize;
11736
11737        for selection in self.selections.all_adjusted(&self.display_snapshot(cx)) {
11738            let selection_is_empty = selection.is_empty();
11739
11740            let (start, end) = if selection_is_empty {
11741                let (word_range, _) = buffer.surrounding_word(selection.start, None);
11742                (word_range.start, word_range.end)
11743            } else {
11744                (
11745                    buffer.point_to_offset(selection.start),
11746                    buffer.point_to_offset(selection.end),
11747                )
11748            };
11749
11750            let text = buffer.text_for_range(start..end).collect::<String>();
11751            let old_length = text.len() as isize;
11752            let text = callback(&text);
11753
11754            new_selections.push(Selection {
11755                start: MultiBufferOffset((start.0 as isize - selection_adjustment) as usize),
11756                end: MultiBufferOffset(
11757                    ((start.0 + text.len()) as isize - selection_adjustment) as usize,
11758                ),
11759                goal: SelectionGoal::None,
11760                id: selection.id,
11761                reversed: selection.reversed,
11762            });
11763
11764            selection_adjustment += old_length - text.len() as isize;
11765
11766            edits.push((start..end, text));
11767        }
11768
11769        self.transact(window, cx, |this, window, cx| {
11770            this.buffer.update(cx, |buffer, cx| {
11771                buffer.edit(edits, None, cx);
11772            });
11773
11774            this.change_selections(Default::default(), window, cx, |s| {
11775                s.select(new_selections);
11776            });
11777
11778            this.request_autoscroll(Autoscroll::fit(), cx);
11779        });
11780    }
11781
11782    pub fn move_selection_on_drop(
11783        &mut self,
11784        selection: &Selection<Anchor>,
11785        target: DisplayPoint,
11786        is_cut: bool,
11787        window: &mut Window,
11788        cx: &mut Context<Self>,
11789    ) {
11790        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11791        let buffer = display_map.buffer_snapshot();
11792        let mut edits = Vec::new();
11793        let insert_point = display_map
11794            .clip_point(target, Bias::Left)
11795            .to_point(&display_map);
11796        let text = buffer
11797            .text_for_range(selection.start..selection.end)
11798            .collect::<String>();
11799        if is_cut {
11800            edits.push(((selection.start..selection.end), String::new()));
11801        }
11802        let insert_anchor = buffer.anchor_before(insert_point);
11803        edits.push(((insert_anchor..insert_anchor), text));
11804        let last_edit_start = insert_anchor.bias_left(buffer);
11805        let last_edit_end = insert_anchor.bias_right(buffer);
11806        self.transact(window, cx, |this, window, cx| {
11807            this.buffer.update(cx, |buffer, cx| {
11808                buffer.edit(edits, None, cx);
11809            });
11810            this.change_selections(Default::default(), window, cx, |s| {
11811                s.select_anchor_ranges([last_edit_start..last_edit_end]);
11812            });
11813        });
11814    }
11815
11816    pub fn clear_selection_drag_state(&mut self) {
11817        self.selection_drag_state = SelectionDragState::None;
11818    }
11819
11820    pub fn duplicate(
11821        &mut self,
11822        upwards: bool,
11823        whole_lines: bool,
11824        window: &mut Window,
11825        cx: &mut Context<Self>,
11826    ) {
11827        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11828
11829        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11830        let buffer = display_map.buffer_snapshot();
11831        let selections = self.selections.all::<Point>(&display_map);
11832
11833        let mut edits = Vec::new();
11834        let mut selections_iter = selections.iter().peekable();
11835        while let Some(selection) = selections_iter.next() {
11836            let mut rows = selection.spanned_rows(false, &display_map);
11837            // duplicate line-wise
11838            if whole_lines || selection.start == selection.end {
11839                // Avoid duplicating the same lines twice.
11840                while let Some(next_selection) = selections_iter.peek() {
11841                    let next_rows = next_selection.spanned_rows(false, &display_map);
11842                    if next_rows.start < rows.end {
11843                        rows.end = next_rows.end;
11844                        selections_iter.next().unwrap();
11845                    } else {
11846                        break;
11847                    }
11848                }
11849
11850                // Copy the text from the selected row region and splice it either at the start
11851                // or end of the region.
11852                let start = Point::new(rows.start.0, 0);
11853                let end = Point::new(
11854                    rows.end.previous_row().0,
11855                    buffer.line_len(rows.end.previous_row()),
11856                );
11857
11858                let mut text = buffer.text_for_range(start..end).collect::<String>();
11859
11860                let insert_location = if upwards {
11861                    // When duplicating upward, we need to insert before the current line.
11862                    // If we're on the last line and it doesn't end with a newline,
11863                    // we need to add a newline before the duplicated content.
11864                    let needs_leading_newline = rows.end.0 >= buffer.max_point().row
11865                        && buffer.max_point().column > 0
11866                        && !text.ends_with('\n');
11867
11868                    if needs_leading_newline {
11869                        text.insert(0, '\n');
11870                        end
11871                    } else {
11872                        text.push('\n');
11873                        Point::new(rows.start.0, 0)
11874                    }
11875                } else {
11876                    text.push('\n');
11877                    start
11878                };
11879                edits.push((insert_location..insert_location, text));
11880            } else {
11881                // duplicate character-wise
11882                let start = selection.start;
11883                let end = selection.end;
11884                let text = buffer.text_for_range(start..end).collect::<String>();
11885                edits.push((selection.end..selection.end, text));
11886            }
11887        }
11888
11889        self.transact(window, cx, |this, window, cx| {
11890            this.buffer.update(cx, |buffer, cx| {
11891                buffer.edit(edits, None, cx);
11892            });
11893
11894            // When duplicating upward with whole lines, move the cursor to the duplicated line
11895            if upwards && whole_lines {
11896                let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
11897
11898                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
11899                    let mut new_ranges = Vec::new();
11900                    let selections = s.all::<Point>(&display_map);
11901                    let mut selections_iter = selections.iter().peekable();
11902
11903                    while let Some(first_selection) = selections_iter.next() {
11904                        // Group contiguous selections together to find the total row span
11905                        let mut group_selections = vec![first_selection];
11906                        let mut rows = first_selection.spanned_rows(false, &display_map);
11907
11908                        while let Some(next_selection) = selections_iter.peek() {
11909                            let next_rows = next_selection.spanned_rows(false, &display_map);
11910                            if next_rows.start < rows.end {
11911                                rows.end = next_rows.end;
11912                                group_selections.push(selections_iter.next().unwrap());
11913                            } else {
11914                                break;
11915                            }
11916                        }
11917
11918                        let row_count = rows.end.0 - rows.start.0;
11919
11920                        // Move all selections in this group up by the total number of duplicated rows
11921                        for selection in group_selections {
11922                            let new_start = Point::new(
11923                                selection.start.row.saturating_sub(row_count),
11924                                selection.start.column,
11925                            );
11926
11927                            let new_end = Point::new(
11928                                selection.end.row.saturating_sub(row_count),
11929                                selection.end.column,
11930                            );
11931
11932                            new_ranges.push(new_start..new_end);
11933                        }
11934                    }
11935
11936                    s.select_ranges(new_ranges);
11937                });
11938            }
11939
11940            this.request_autoscroll(Autoscroll::fit(), cx);
11941        });
11942    }
11943
11944    pub fn duplicate_line_up(
11945        &mut self,
11946        _: &DuplicateLineUp,
11947        window: &mut Window,
11948        cx: &mut Context<Self>,
11949    ) {
11950        self.duplicate(true, true, window, cx);
11951    }
11952
11953    pub fn duplicate_line_down(
11954        &mut self,
11955        _: &DuplicateLineDown,
11956        window: &mut Window,
11957        cx: &mut Context<Self>,
11958    ) {
11959        self.duplicate(false, true, window, cx);
11960    }
11961
11962    pub fn duplicate_selection(
11963        &mut self,
11964        _: &DuplicateSelection,
11965        window: &mut Window,
11966        cx: &mut Context<Self>,
11967    ) {
11968        self.duplicate(false, false, window, cx);
11969    }
11970
11971    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
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 before the line preceding the row range
12000            if start_row.0 > 0 {
12001                let range_to_move = Point::new(
12002                    start_row.previous_row().0,
12003                    buffer.line_len(start_row.previous_row()),
12004                )
12005                    ..Point::new(
12006                        end_row.previous_row().0,
12007                        buffer.line_len(end_row.previous_row()),
12008                    );
12009                let insertion_point = display_map
12010                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
12011                    .0;
12012
12013                // Don't move lines across excerpts
12014                if buffer
12015                    .excerpt_containing(insertion_point..range_to_move.end)
12016                    .is_some()
12017                {
12018                    let text = buffer
12019                        .text_for_range(range_to_move.clone())
12020                        .flat_map(|s| s.chars())
12021                        .skip(1)
12022                        .chain(['\n'])
12023                        .collect::<String>();
12024
12025                    edits.push((
12026                        buffer.anchor_after(range_to_move.start)
12027                            ..buffer.anchor_before(range_to_move.end),
12028                        String::new(),
12029                    ));
12030                    let insertion_anchor = buffer.anchor_after(insertion_point);
12031                    edits.push((insertion_anchor..insertion_anchor, text));
12032
12033                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
12034
12035                    // Move selections up
12036                    new_selections.extend(contiguous_row_selections.drain(..).map(
12037                        |mut selection| {
12038                            selection.start.row -= row_delta;
12039                            selection.end.row -= row_delta;
12040                            selection
12041                        },
12042                    ));
12043
12044                    // Move folds up
12045                    unfold_ranges.push(range_to_move.clone());
12046                    for fold in display_map.folds_in_range(
12047                        buffer.anchor_before(range_to_move.start)
12048                            ..buffer.anchor_after(range_to_move.end),
12049                    ) {
12050                        let mut start = fold.range.start.to_point(&buffer);
12051                        let mut end = fold.range.end.to_point(&buffer);
12052                        start.row -= row_delta;
12053                        end.row -= row_delta;
12054                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
12055                    }
12056                }
12057            }
12058
12059            // If we didn't move line(s), preserve the existing selections
12060            new_selections.append(&mut contiguous_row_selections);
12061        }
12062
12063        self.transact(window, cx, |this, window, cx| {
12064            this.unfold_ranges(&unfold_ranges, true, true, cx);
12065            this.buffer.update(cx, |buffer, cx| {
12066                for (range, text) in edits {
12067                    buffer.edit([(range, text)], None, cx);
12068                }
12069            });
12070            this.fold_creases(refold_creases, true, window, cx);
12071            this.change_selections(Default::default(), window, cx, |s| {
12072                s.select(new_selections);
12073            })
12074        });
12075    }
12076
12077    pub fn move_line_down(
12078        &mut self,
12079        _: &MoveLineDown,
12080        window: &mut Window,
12081        cx: &mut Context<Self>,
12082    ) {
12083        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12084        if self.mode.is_single_line() {
12085            cx.propagate();
12086            return;
12087        }
12088
12089        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12090        let buffer = self.buffer.read(cx).snapshot(cx);
12091
12092        let mut edits = Vec::new();
12093        let mut unfold_ranges = Vec::new();
12094        let mut refold_creases = Vec::new();
12095
12096        let selections = self.selections.all::<Point>(&display_map);
12097        let mut selections = selections.iter().peekable();
12098        let mut contiguous_row_selections = Vec::new();
12099        let mut new_selections = Vec::new();
12100
12101        while let Some(selection) = selections.next() {
12102            // Find all the selections that span a contiguous row range
12103            let (start_row, end_row) = consume_contiguous_rows(
12104                &mut contiguous_row_selections,
12105                selection,
12106                &display_map,
12107                &mut selections,
12108            );
12109
12110            // Move the text spanned by the row range to be after the last line of the row range
12111            if end_row.0 <= buffer.max_point().row {
12112                let range_to_move =
12113                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
12114                let insertion_point = display_map
12115                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
12116                    .0;
12117
12118                // Don't move lines across excerpt boundaries
12119                if buffer
12120                    .excerpt_containing(range_to_move.start..insertion_point)
12121                    .is_some()
12122                {
12123                    let mut text = String::from("\n");
12124                    text.extend(buffer.text_for_range(range_to_move.clone()));
12125                    text.pop(); // Drop trailing newline
12126                    edits.push((
12127                        buffer.anchor_after(range_to_move.start)
12128                            ..buffer.anchor_before(range_to_move.end),
12129                        String::new(),
12130                    ));
12131                    let insertion_anchor = buffer.anchor_after(insertion_point);
12132                    edits.push((insertion_anchor..insertion_anchor, text));
12133
12134                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
12135
12136                    // Move selections down
12137                    new_selections.extend(contiguous_row_selections.drain(..).map(
12138                        |mut selection| {
12139                            selection.start.row += row_delta;
12140                            selection.end.row += row_delta;
12141                            selection
12142                        },
12143                    ));
12144
12145                    // Move folds down
12146                    unfold_ranges.push(range_to_move.clone());
12147                    for fold in display_map.folds_in_range(
12148                        buffer.anchor_before(range_to_move.start)
12149                            ..buffer.anchor_after(range_to_move.end),
12150                    ) {
12151                        let mut start = fold.range.start.to_point(&buffer);
12152                        let mut end = fold.range.end.to_point(&buffer);
12153                        start.row += row_delta;
12154                        end.row += row_delta;
12155                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
12156                    }
12157                }
12158            }
12159
12160            // If we didn't move line(s), preserve the existing selections
12161            new_selections.append(&mut contiguous_row_selections);
12162        }
12163
12164        self.transact(window, cx, |this, window, cx| {
12165            this.unfold_ranges(&unfold_ranges, true, true, cx);
12166            this.buffer.update(cx, |buffer, cx| {
12167                for (range, text) in edits {
12168                    buffer.edit([(range, text)], None, cx);
12169                }
12170            });
12171            this.fold_creases(refold_creases, true, window, cx);
12172            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
12173        });
12174    }
12175
12176    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
12177        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12178        let text_layout_details = &self.text_layout_details(window);
12179        self.transact(window, cx, |this, window, cx| {
12180            let edits = this.change_selections(Default::default(), window, cx, |s| {
12181                let mut edits: Vec<(Range<MultiBufferOffset>, String)> = Default::default();
12182                s.move_with(|display_map, selection| {
12183                    if !selection.is_empty() {
12184                        return;
12185                    }
12186
12187                    let mut head = selection.head();
12188                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
12189                    if head.column() == display_map.line_len(head.row()) {
12190                        transpose_offset = display_map
12191                            .buffer_snapshot()
12192                            .clip_offset(transpose_offset.saturating_sub_usize(1), Bias::Left);
12193                    }
12194
12195                    if transpose_offset == MultiBufferOffset(0) {
12196                        return;
12197                    }
12198
12199                    *head.column_mut() += 1;
12200                    head = display_map.clip_point(head, Bias::Right);
12201                    let goal = SelectionGoal::HorizontalPosition(
12202                        display_map
12203                            .x_for_display_point(head, text_layout_details)
12204                            .into(),
12205                    );
12206                    selection.collapse_to(head, goal);
12207
12208                    let transpose_start = display_map
12209                        .buffer_snapshot()
12210                        .clip_offset(transpose_offset.saturating_sub_usize(1), Bias::Left);
12211                    if edits.last().is_none_or(|e| e.0.end <= transpose_start) {
12212                        let transpose_end = display_map
12213                            .buffer_snapshot()
12214                            .clip_offset(transpose_offset + 1usize, Bias::Right);
12215                        if let Some(ch) = display_map
12216                            .buffer_snapshot()
12217                            .chars_at(transpose_start)
12218                            .next()
12219                        {
12220                            edits.push((transpose_start..transpose_offset, String::new()));
12221                            edits.push((transpose_end..transpose_end, ch.to_string()));
12222                        }
12223                    }
12224                });
12225                edits
12226            });
12227            this.buffer
12228                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12229            let selections = this
12230                .selections
12231                .all::<MultiBufferOffset>(&this.display_snapshot(cx));
12232            this.change_selections(Default::default(), window, cx, |s| {
12233                s.select(selections);
12234            });
12235        });
12236    }
12237
12238    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
12239        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12240        if self.mode.is_single_line() {
12241            cx.propagate();
12242            return;
12243        }
12244
12245        self.rewrap_impl(RewrapOptions::default(), cx)
12246    }
12247
12248    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
12249        let buffer = self.buffer.read(cx).snapshot(cx);
12250        let selections = self.selections.all::<Point>(&self.display_snapshot(cx));
12251
12252        #[derive(Clone, Debug, PartialEq)]
12253        enum CommentFormat {
12254            /// single line comment, with prefix for line
12255            Line(String),
12256            /// single line within a block comment, with prefix for line
12257            BlockLine(String),
12258            /// a single line of a block comment that includes the initial delimiter
12259            BlockCommentWithStart(BlockCommentConfig),
12260            /// a single line of a block comment that includes the ending delimiter
12261            BlockCommentWithEnd(BlockCommentConfig),
12262        }
12263
12264        // Split selections to respect paragraph, indent, and comment prefix boundaries.
12265        let wrap_ranges = selections.into_iter().flat_map(|selection| {
12266            let mut non_blank_rows_iter = (selection.start.row..=selection.end.row)
12267                .filter(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
12268                .peekable();
12269
12270            let first_row = if let Some(&row) = non_blank_rows_iter.peek() {
12271                row
12272            } else {
12273                return Vec::new();
12274            };
12275
12276            let language_settings = buffer.language_settings_at(selection.head(), cx);
12277            let language_scope = buffer.language_scope_at(selection.head());
12278
12279            let indent_and_prefix_for_row =
12280                |row: u32| -> (IndentSize, Option<CommentFormat>, Option<String>) {
12281                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
12282                    let (comment_prefix, rewrap_prefix) = if let Some(language_scope) =
12283                        &language_scope
12284                    {
12285                        let indent_end = Point::new(row, indent.len);
12286                        let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
12287                        let line_text_after_indent = buffer
12288                            .text_for_range(indent_end..line_end)
12289                            .collect::<String>();
12290
12291                        let is_within_comment_override = buffer
12292                            .language_scope_at(indent_end)
12293                            .is_some_and(|scope| scope.override_name() == Some("comment"));
12294                        let comment_delimiters = if is_within_comment_override {
12295                            // we are within a comment syntax node, but we don't
12296                            // yet know what kind of comment: block, doc or line
12297                            match (
12298                                language_scope.documentation_comment(),
12299                                language_scope.block_comment(),
12300                            ) {
12301                                (Some(config), _) | (_, Some(config))
12302                                    if buffer.contains_str_at(indent_end, &config.start) =>
12303                                {
12304                                    Some(CommentFormat::BlockCommentWithStart(config.clone()))
12305                                }
12306                                (Some(config), _) | (_, Some(config))
12307                                    if line_text_after_indent.ends_with(config.end.as_ref()) =>
12308                                {
12309                                    Some(CommentFormat::BlockCommentWithEnd(config.clone()))
12310                                }
12311                                (Some(config), _) | (_, Some(config))
12312                                    if buffer.contains_str_at(indent_end, &config.prefix) =>
12313                                {
12314                                    Some(CommentFormat::BlockLine(config.prefix.to_string()))
12315                                }
12316                                (_, _) => language_scope
12317                                    .line_comment_prefixes()
12318                                    .iter()
12319                                    .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12320                                    .map(|prefix| CommentFormat::Line(prefix.to_string())),
12321                            }
12322                        } else {
12323                            // we not in an overridden comment node, but we may
12324                            // be within a non-overridden line comment node
12325                            language_scope
12326                                .line_comment_prefixes()
12327                                .iter()
12328                                .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12329                                .map(|prefix| CommentFormat::Line(prefix.to_string()))
12330                        };
12331
12332                        let rewrap_prefix = language_scope
12333                            .rewrap_prefixes()
12334                            .iter()
12335                            .find_map(|prefix_regex| {
12336                                prefix_regex.find(&line_text_after_indent).map(|mat| {
12337                                    if mat.start() == 0 {
12338                                        Some(mat.as_str().to_string())
12339                                    } else {
12340                                        None
12341                                    }
12342                                })
12343                            })
12344                            .flatten();
12345                        (comment_delimiters, rewrap_prefix)
12346                    } else {
12347                        (None, None)
12348                    };
12349                    (indent, comment_prefix, rewrap_prefix)
12350                };
12351
12352            let mut ranges = Vec::new();
12353            let from_empty_selection = selection.is_empty();
12354
12355            let mut current_range_start = first_row;
12356            let mut prev_row = first_row;
12357            let (
12358                mut current_range_indent,
12359                mut current_range_comment_delimiters,
12360                mut current_range_rewrap_prefix,
12361            ) = indent_and_prefix_for_row(first_row);
12362
12363            for row in non_blank_rows_iter.skip(1) {
12364                let has_paragraph_break = row > prev_row + 1;
12365
12366                let (row_indent, row_comment_delimiters, row_rewrap_prefix) =
12367                    indent_and_prefix_for_row(row);
12368
12369                let has_indent_change = row_indent != current_range_indent;
12370                let has_comment_change = row_comment_delimiters != current_range_comment_delimiters;
12371
12372                let has_boundary_change = has_comment_change
12373                    || row_rewrap_prefix.is_some()
12374                    || (has_indent_change && current_range_comment_delimiters.is_some());
12375
12376                if has_paragraph_break || has_boundary_change {
12377                    ranges.push((
12378                        language_settings.clone(),
12379                        Point::new(current_range_start, 0)
12380                            ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12381                        current_range_indent,
12382                        current_range_comment_delimiters.clone(),
12383                        current_range_rewrap_prefix.clone(),
12384                        from_empty_selection,
12385                    ));
12386                    current_range_start = row;
12387                    current_range_indent = row_indent;
12388                    current_range_comment_delimiters = row_comment_delimiters;
12389                    current_range_rewrap_prefix = row_rewrap_prefix;
12390                }
12391                prev_row = row;
12392            }
12393
12394            ranges.push((
12395                language_settings.clone(),
12396                Point::new(current_range_start, 0)
12397                    ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12398                current_range_indent,
12399                current_range_comment_delimiters,
12400                current_range_rewrap_prefix,
12401                from_empty_selection,
12402            ));
12403
12404            ranges
12405        });
12406
12407        let mut edits = Vec::new();
12408        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
12409
12410        for (
12411            language_settings,
12412            wrap_range,
12413            mut indent_size,
12414            comment_prefix,
12415            rewrap_prefix,
12416            from_empty_selection,
12417        ) in wrap_ranges
12418        {
12419            let mut start_row = wrap_range.start.row;
12420            let mut end_row = wrap_range.end.row;
12421
12422            // Skip selections that overlap with a range that has already been rewrapped.
12423            let selection_range = start_row..end_row;
12424            if rewrapped_row_ranges
12425                .iter()
12426                .any(|range| range.overlaps(&selection_range))
12427            {
12428                continue;
12429            }
12430
12431            let tab_size = language_settings.tab_size;
12432
12433            let (line_prefix, inside_comment) = match &comment_prefix {
12434                Some(CommentFormat::Line(prefix) | CommentFormat::BlockLine(prefix)) => {
12435                    (Some(prefix.as_str()), true)
12436                }
12437                Some(CommentFormat::BlockCommentWithEnd(BlockCommentConfig { prefix, .. })) => {
12438                    (Some(prefix.as_ref()), true)
12439                }
12440                Some(CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12441                    start: _,
12442                    end: _,
12443                    prefix,
12444                    tab_size,
12445                })) => {
12446                    indent_size.len += tab_size;
12447                    (Some(prefix.as_ref()), true)
12448                }
12449                None => (None, false),
12450            };
12451            let indent_prefix = indent_size.chars().collect::<String>();
12452            let line_prefix = format!("{indent_prefix}{}", line_prefix.unwrap_or(""));
12453
12454            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
12455                RewrapBehavior::InComments => inside_comment,
12456                RewrapBehavior::InSelections => !wrap_range.is_empty(),
12457                RewrapBehavior::Anywhere => true,
12458            };
12459
12460            let should_rewrap = options.override_language_settings
12461                || allow_rewrap_based_on_language
12462                || self.hard_wrap.is_some();
12463            if !should_rewrap {
12464                continue;
12465            }
12466
12467            if from_empty_selection {
12468                'expand_upwards: while start_row > 0 {
12469                    let prev_row = start_row - 1;
12470                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
12471                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
12472                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
12473                    {
12474                        start_row = prev_row;
12475                    } else {
12476                        break 'expand_upwards;
12477                    }
12478                }
12479
12480                'expand_downwards: while end_row < buffer.max_point().row {
12481                    let next_row = end_row + 1;
12482                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
12483                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
12484                        && !buffer.is_line_blank(MultiBufferRow(next_row))
12485                    {
12486                        end_row = next_row;
12487                    } else {
12488                        break 'expand_downwards;
12489                    }
12490                }
12491            }
12492
12493            let start = Point::new(start_row, 0);
12494            let start_offset = ToOffset::to_offset(&start, &buffer);
12495            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
12496            let selection_text = buffer.text_for_range(start..end).collect::<String>();
12497            let mut first_line_delimiter = None;
12498            let mut last_line_delimiter = None;
12499            let Some(lines_without_prefixes) = selection_text
12500                .lines()
12501                .enumerate()
12502                .map(|(ix, line)| {
12503                    let line_trimmed = line.trim_start();
12504                    if rewrap_prefix.is_some() && ix > 0 {
12505                        Ok(line_trimmed)
12506                    } else if let Some(
12507                        CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12508                            start,
12509                            prefix,
12510                            end,
12511                            tab_size,
12512                        })
12513                        | CommentFormat::BlockCommentWithEnd(BlockCommentConfig {
12514                            start,
12515                            prefix,
12516                            end,
12517                            tab_size,
12518                        }),
12519                    ) = &comment_prefix
12520                    {
12521                        let line_trimmed = line_trimmed
12522                            .strip_prefix(start.as_ref())
12523                            .map(|s| {
12524                                let mut indent_size = indent_size;
12525                                indent_size.len -= tab_size;
12526                                let indent_prefix: String = indent_size.chars().collect();
12527                                first_line_delimiter = Some((indent_prefix, start));
12528                                s.trim_start()
12529                            })
12530                            .unwrap_or(line_trimmed);
12531                        let line_trimmed = line_trimmed
12532                            .strip_suffix(end.as_ref())
12533                            .map(|s| {
12534                                last_line_delimiter = Some(end);
12535                                s.trim_end()
12536                            })
12537                            .unwrap_or(line_trimmed);
12538                        let line_trimmed = line_trimmed
12539                            .strip_prefix(prefix.as_ref())
12540                            .unwrap_or(line_trimmed);
12541                        Ok(line_trimmed)
12542                    } else if let Some(CommentFormat::BlockLine(prefix)) = &comment_prefix {
12543                        line_trimmed.strip_prefix(prefix).with_context(|| {
12544                            format!("line did not start with prefix {prefix:?}: {line:?}")
12545                        })
12546                    } else {
12547                        line_trimmed
12548                            .strip_prefix(&line_prefix.trim_start())
12549                            .with_context(|| {
12550                                format!("line did not start with prefix {line_prefix:?}: {line:?}")
12551                            })
12552                    }
12553                })
12554                .collect::<Result<Vec<_>, _>>()
12555                .log_err()
12556            else {
12557                continue;
12558            };
12559
12560            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
12561                buffer
12562                    .language_settings_at(Point::new(start_row, 0), cx)
12563                    .preferred_line_length as usize
12564            });
12565
12566            let subsequent_lines_prefix = if let Some(rewrap_prefix_str) = &rewrap_prefix {
12567                format!("{}{}", indent_prefix, " ".repeat(rewrap_prefix_str.len()))
12568            } else {
12569                line_prefix.clone()
12570            };
12571
12572            let wrapped_text = {
12573                let mut wrapped_text = wrap_with_prefix(
12574                    line_prefix,
12575                    subsequent_lines_prefix,
12576                    lines_without_prefixes.join("\n"),
12577                    wrap_column,
12578                    tab_size,
12579                    options.preserve_existing_whitespace,
12580                );
12581
12582                if let Some((indent, delimiter)) = first_line_delimiter {
12583                    wrapped_text = format!("{indent}{delimiter}\n{wrapped_text}");
12584                }
12585                if let Some(last_line) = last_line_delimiter {
12586                    wrapped_text = format!("{wrapped_text}\n{indent_prefix}{last_line}");
12587                }
12588
12589                wrapped_text
12590            };
12591
12592            // TODO: should always use char-based diff while still supporting cursor behavior that
12593            // matches vim.
12594            let mut diff_options = DiffOptions::default();
12595            if options.override_language_settings {
12596                diff_options.max_word_diff_len = 0;
12597                diff_options.max_word_diff_line_count = 0;
12598            } else {
12599                diff_options.max_word_diff_len = usize::MAX;
12600                diff_options.max_word_diff_line_count = usize::MAX;
12601            }
12602
12603            for (old_range, new_text) in
12604                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
12605            {
12606                let edit_start = buffer.anchor_after(start_offset + old_range.start);
12607                let edit_end = buffer.anchor_after(start_offset + old_range.end);
12608                edits.push((edit_start..edit_end, new_text));
12609            }
12610
12611            rewrapped_row_ranges.push(start_row..=end_row);
12612        }
12613
12614        self.buffer
12615            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12616    }
12617
12618    pub fn cut_common(
12619        &mut self,
12620        cut_no_selection_line: bool,
12621        window: &mut Window,
12622        cx: &mut Context<Self>,
12623    ) -> ClipboardItem {
12624        let mut text = String::new();
12625        let buffer = self.buffer.read(cx).snapshot(cx);
12626        let mut selections = self.selections.all::<Point>(&self.display_snapshot(cx));
12627        let mut clipboard_selections = Vec::with_capacity(selections.len());
12628        {
12629            let max_point = buffer.max_point();
12630            let mut is_first = true;
12631            let mut prev_selection_was_entire_line = false;
12632            for selection in &mut selections {
12633                let is_entire_line =
12634                    (selection.is_empty() && cut_no_selection_line) || self.selections.line_mode();
12635                if is_entire_line {
12636                    selection.start = Point::new(selection.start.row, 0);
12637                    if !selection.is_empty() && selection.end.column == 0 {
12638                        selection.end = cmp::min(max_point, selection.end);
12639                    } else {
12640                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
12641                    }
12642                    selection.goal = SelectionGoal::None;
12643                }
12644                if is_first {
12645                    is_first = false;
12646                } else if !prev_selection_was_entire_line {
12647                    text += "\n";
12648                }
12649                prev_selection_was_entire_line = is_entire_line;
12650                let mut len = 0;
12651                for chunk in buffer.text_for_range(selection.start..selection.end) {
12652                    text.push_str(chunk);
12653                    len += chunk.len();
12654                }
12655                clipboard_selections.push(ClipboardSelection {
12656                    len,
12657                    is_entire_line,
12658                    first_line_indent: buffer
12659                        .indent_size_for_line(MultiBufferRow(selection.start.row))
12660                        .len,
12661                });
12662            }
12663        }
12664
12665        self.transact(window, cx, |this, window, cx| {
12666            this.change_selections(Default::default(), window, cx, |s| {
12667                s.select(selections);
12668            });
12669            this.insert("", window, cx);
12670        });
12671        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
12672    }
12673
12674    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
12675        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12676        let item = self.cut_common(true, window, cx);
12677        cx.write_to_clipboard(item);
12678    }
12679
12680    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
12681        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12682        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12683            s.move_with(|snapshot, sel| {
12684                if sel.is_empty() {
12685                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()));
12686                }
12687                if sel.is_empty() {
12688                    sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
12689                }
12690            });
12691        });
12692        let item = self.cut_common(false, window, cx);
12693        cx.set_global(KillRing(item))
12694    }
12695
12696    pub fn kill_ring_yank(
12697        &mut self,
12698        _: &KillRingYank,
12699        window: &mut Window,
12700        cx: &mut Context<Self>,
12701    ) {
12702        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12703        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
12704            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
12705                (kill_ring.text().to_string(), kill_ring.metadata_json())
12706            } else {
12707                return;
12708            }
12709        } else {
12710            return;
12711        };
12712        self.do_paste(&text, metadata, false, window, cx);
12713    }
12714
12715    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
12716        self.do_copy(true, cx);
12717    }
12718
12719    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
12720        self.do_copy(false, cx);
12721    }
12722
12723    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
12724        let selections = self.selections.all::<Point>(&self.display_snapshot(cx));
12725        let buffer = self.buffer.read(cx).read(cx);
12726        let mut text = String::new();
12727
12728        let mut clipboard_selections = Vec::with_capacity(selections.len());
12729        {
12730            let max_point = buffer.max_point();
12731            let mut is_first = true;
12732            let mut prev_selection_was_entire_line = false;
12733            for selection in &selections {
12734                let mut start = selection.start;
12735                let mut end = selection.end;
12736                let is_entire_line = selection.is_empty() || self.selections.line_mode();
12737                let mut add_trailing_newline = false;
12738                if is_entire_line {
12739                    start = Point::new(start.row, 0);
12740                    let next_line_start = Point::new(end.row + 1, 0);
12741                    if next_line_start <= max_point {
12742                        end = next_line_start;
12743                    } else {
12744                        // We're on the last line without a trailing newline.
12745                        // Copy to the end of the line and add a newline afterwards.
12746                        end = Point::new(end.row, buffer.line_len(MultiBufferRow(end.row)));
12747                        add_trailing_newline = true;
12748                    }
12749                }
12750
12751                let mut trimmed_selections = Vec::new();
12752                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
12753                    let row = MultiBufferRow(start.row);
12754                    let first_indent = buffer.indent_size_for_line(row);
12755                    if first_indent.len == 0 || start.column > first_indent.len {
12756                        trimmed_selections.push(start..end);
12757                    } else {
12758                        trimmed_selections.push(
12759                            Point::new(row.0, first_indent.len)
12760                                ..Point::new(row.0, buffer.line_len(row)),
12761                        );
12762                        for row in start.row + 1..=end.row {
12763                            let mut line_len = buffer.line_len(MultiBufferRow(row));
12764                            if row == end.row {
12765                                line_len = end.column;
12766                            }
12767                            if line_len == 0 {
12768                                trimmed_selections
12769                                    .push(Point::new(row, 0)..Point::new(row, line_len));
12770                                continue;
12771                            }
12772                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
12773                            if row_indent_size.len >= first_indent.len {
12774                                trimmed_selections.push(
12775                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
12776                                );
12777                            } else {
12778                                trimmed_selections.clear();
12779                                trimmed_selections.push(start..end);
12780                                break;
12781                            }
12782                        }
12783                    }
12784                } else {
12785                    trimmed_selections.push(start..end);
12786                }
12787
12788                for trimmed_range in trimmed_selections {
12789                    if is_first {
12790                        is_first = false;
12791                    } else if !prev_selection_was_entire_line {
12792                        text += "\n";
12793                    }
12794                    prev_selection_was_entire_line = is_entire_line;
12795                    let mut len = 0;
12796                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
12797                        text.push_str(chunk);
12798                        len += chunk.len();
12799                    }
12800                    if add_trailing_newline {
12801                        text.push('\n');
12802                        len += 1;
12803                    }
12804                    clipboard_selections.push(ClipboardSelection {
12805                        len,
12806                        is_entire_line,
12807                        first_line_indent: buffer
12808                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
12809                            .len,
12810                    });
12811                }
12812            }
12813        }
12814
12815        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
12816            text,
12817            clipboard_selections,
12818        ));
12819    }
12820
12821    pub fn do_paste(
12822        &mut self,
12823        text: &String,
12824        clipboard_selections: Option<Vec<ClipboardSelection>>,
12825        handle_entire_lines: bool,
12826        window: &mut Window,
12827        cx: &mut Context<Self>,
12828    ) {
12829        if self.read_only(cx) {
12830            return;
12831        }
12832
12833        let clipboard_text = Cow::Borrowed(text.as_str());
12834
12835        self.transact(window, cx, |this, window, cx| {
12836            let had_active_edit_prediction = this.has_active_edit_prediction();
12837            let display_map = this.display_snapshot(cx);
12838            let old_selections = this.selections.all::<MultiBufferOffset>(&display_map);
12839            let cursor_offset = this
12840                .selections
12841                .last::<MultiBufferOffset>(&display_map)
12842                .head();
12843
12844            if let Some(mut clipboard_selections) = clipboard_selections {
12845                let all_selections_were_entire_line =
12846                    clipboard_selections.iter().all(|s| s.is_entire_line);
12847                let first_selection_indent_column =
12848                    clipboard_selections.first().map(|s| s.first_line_indent);
12849                if clipboard_selections.len() != old_selections.len() {
12850                    clipboard_selections.drain(..);
12851                }
12852                let mut auto_indent_on_paste = true;
12853
12854                this.buffer.update(cx, |buffer, cx| {
12855                    let snapshot = buffer.read(cx);
12856                    auto_indent_on_paste = snapshot
12857                        .language_settings_at(cursor_offset, cx)
12858                        .auto_indent_on_paste;
12859
12860                    let mut start_offset = 0;
12861                    let mut edits = Vec::new();
12862                    let mut original_indent_columns = Vec::new();
12863                    for (ix, selection) in old_selections.iter().enumerate() {
12864                        let to_insert;
12865                        let entire_line;
12866                        let original_indent_column;
12867                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
12868                            let end_offset = start_offset + clipboard_selection.len;
12869                            to_insert = &clipboard_text[start_offset..end_offset];
12870                            entire_line = clipboard_selection.is_entire_line;
12871                            start_offset = if entire_line {
12872                                end_offset
12873                            } else {
12874                                end_offset + 1
12875                            };
12876                            original_indent_column = Some(clipboard_selection.first_line_indent);
12877                        } else {
12878                            to_insert = &*clipboard_text;
12879                            entire_line = all_selections_were_entire_line;
12880                            original_indent_column = first_selection_indent_column
12881                        }
12882
12883                        let (range, to_insert) =
12884                            if selection.is_empty() && handle_entire_lines && entire_line {
12885                                // If the corresponding selection was empty when this slice of the
12886                                // clipboard text was written, then the entire line containing the
12887                                // selection was copied. If this selection is also currently empty,
12888                                // then paste the line before the current line of the buffer.
12889                                let column = selection.start.to_point(&snapshot).column as usize;
12890                                let line_start = selection.start - column;
12891                                (line_start..line_start, Cow::Borrowed(to_insert))
12892                            } else {
12893                                let language = snapshot.language_at(selection.head());
12894                                let range = selection.range();
12895                                if let Some(language) = language
12896                                    && language.name() == "Markdown".into()
12897                                {
12898                                    edit_for_markdown_paste(
12899                                        &snapshot,
12900                                        range,
12901                                        to_insert,
12902                                        url::Url::parse(to_insert).ok(),
12903                                    )
12904                                } else {
12905                                    (range, Cow::Borrowed(to_insert))
12906                                }
12907                            };
12908
12909                        edits.push((range, to_insert));
12910                        original_indent_columns.push(original_indent_column);
12911                    }
12912                    drop(snapshot);
12913
12914                    buffer.edit(
12915                        edits,
12916                        if auto_indent_on_paste {
12917                            Some(AutoindentMode::Block {
12918                                original_indent_columns,
12919                            })
12920                        } else {
12921                            None
12922                        },
12923                        cx,
12924                    );
12925                });
12926
12927                let selections = this
12928                    .selections
12929                    .all::<MultiBufferOffset>(&this.display_snapshot(cx));
12930                this.change_selections(Default::default(), window, cx, |s| s.select(selections));
12931            } else {
12932                let url = url::Url::parse(&clipboard_text).ok();
12933
12934                let auto_indent_mode = if !clipboard_text.is_empty() {
12935                    Some(AutoindentMode::Block {
12936                        original_indent_columns: Vec::new(),
12937                    })
12938                } else {
12939                    None
12940                };
12941
12942                let selection_anchors = this.buffer.update(cx, |buffer, cx| {
12943                    let snapshot = buffer.snapshot(cx);
12944
12945                    let anchors = old_selections
12946                        .iter()
12947                        .map(|s| {
12948                            let anchor = snapshot.anchor_after(s.head());
12949                            s.map(|_| anchor)
12950                        })
12951                        .collect::<Vec<_>>();
12952
12953                    let mut edits = Vec::new();
12954
12955                    for selection in old_selections.iter() {
12956                        let language = snapshot.language_at(selection.head());
12957                        let range = selection.range();
12958
12959                        let (edit_range, edit_text) = if let Some(language) = language
12960                            && language.name() == "Markdown".into()
12961                        {
12962                            edit_for_markdown_paste(&snapshot, range, &clipboard_text, url.clone())
12963                        } else {
12964                            (range, clipboard_text.clone())
12965                        };
12966
12967                        edits.push((edit_range, edit_text));
12968                    }
12969
12970                    drop(snapshot);
12971                    buffer.edit(edits, auto_indent_mode, cx);
12972
12973                    anchors
12974                });
12975
12976                this.change_selections(Default::default(), window, cx, |s| {
12977                    s.select_anchors(selection_anchors);
12978                });
12979            }
12980
12981            //   🤔                 |    ..     | show_in_menu |
12982            // | ..                  |   true        true
12983            // | had_edit_prediction |   false       true
12984
12985            let trigger_in_words =
12986                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
12987
12988            this.trigger_completion_on_input(text, trigger_in_words, window, cx);
12989        });
12990    }
12991
12992    pub fn diff_clipboard_with_selection(
12993        &mut self,
12994        _: &DiffClipboardWithSelection,
12995        window: &mut Window,
12996        cx: &mut Context<Self>,
12997    ) {
12998        let selections = self
12999            .selections
13000            .all::<MultiBufferOffset>(&self.display_snapshot(cx));
13001
13002        if selections.is_empty() {
13003            log::warn!("There should always be at least one selection in Zed. This is a bug.");
13004            return;
13005        };
13006
13007        let clipboard_text = match cx.read_from_clipboard() {
13008            Some(item) => match item.entries().first() {
13009                Some(ClipboardEntry::String(text)) => Some(text.text().to_string()),
13010                _ => None,
13011            },
13012            None => None,
13013        };
13014
13015        let Some(clipboard_text) = clipboard_text else {
13016            log::warn!("Clipboard doesn't contain text.");
13017            return;
13018        };
13019
13020        window.dispatch_action(
13021            Box::new(DiffClipboardWithSelectionData {
13022                clipboard_text,
13023                editor: cx.entity(),
13024            }),
13025            cx,
13026        );
13027    }
13028
13029    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
13030        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13031        if let Some(item) = cx.read_from_clipboard() {
13032            let entries = item.entries();
13033
13034            match entries.first() {
13035                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
13036                // of all the pasted entries.
13037                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
13038                    .do_paste(
13039                        clipboard_string.text(),
13040                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
13041                        true,
13042                        window,
13043                        cx,
13044                    ),
13045                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
13046            }
13047        }
13048    }
13049
13050    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
13051        if self.read_only(cx) {
13052            return;
13053        }
13054
13055        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13056
13057        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
13058            if let Some((selections, _)) =
13059                self.selection_history.transaction(transaction_id).cloned()
13060            {
13061                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13062                    s.select_anchors(selections.to_vec());
13063                });
13064            } else {
13065                log::error!(
13066                    "No entry in selection_history found for undo. \
13067                     This may correspond to a bug where undo does not update the selection. \
13068                     If this is occurring, please add details to \
13069                     https://github.com/zed-industries/zed/issues/22692"
13070                );
13071            }
13072            self.request_autoscroll(Autoscroll::fit(), cx);
13073            self.unmark_text(window, cx);
13074            self.refresh_edit_prediction(true, false, window, cx);
13075            cx.emit(EditorEvent::Edited { transaction_id });
13076            cx.emit(EditorEvent::TransactionUndone { transaction_id });
13077        }
13078    }
13079
13080    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
13081        if self.read_only(cx) {
13082            return;
13083        }
13084
13085        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13086
13087        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
13088            if let Some((_, Some(selections))) =
13089                self.selection_history.transaction(transaction_id).cloned()
13090            {
13091                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13092                    s.select_anchors(selections.to_vec());
13093                });
13094            } else {
13095                log::error!(
13096                    "No entry in selection_history found for redo. \
13097                     This may correspond to a bug where undo does not update the selection. \
13098                     If this is occurring, please add details to \
13099                     https://github.com/zed-industries/zed/issues/22692"
13100                );
13101            }
13102            self.request_autoscroll(Autoscroll::fit(), cx);
13103            self.unmark_text(window, cx);
13104            self.refresh_edit_prediction(true, false, window, cx);
13105            cx.emit(EditorEvent::Edited { transaction_id });
13106        }
13107    }
13108
13109    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
13110        self.buffer
13111            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
13112    }
13113
13114    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
13115        self.buffer
13116            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
13117    }
13118
13119    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
13120        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13121        self.change_selections(Default::default(), window, cx, |s| {
13122            s.move_with(|map, selection| {
13123                let cursor = if selection.is_empty() {
13124                    movement::left(map, selection.start)
13125                } else {
13126                    selection.start
13127                };
13128                selection.collapse_to(cursor, SelectionGoal::None);
13129            });
13130        })
13131    }
13132
13133    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
13134        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13135        self.change_selections(Default::default(), window, cx, |s| {
13136            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
13137        })
13138    }
13139
13140    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
13141        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13142        self.change_selections(Default::default(), window, cx, |s| {
13143            s.move_with(|map, selection| {
13144                let cursor = if selection.is_empty() {
13145                    movement::right(map, selection.end)
13146                } else {
13147                    selection.end
13148                };
13149                selection.collapse_to(cursor, SelectionGoal::None)
13150            });
13151        })
13152    }
13153
13154    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
13155        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13156        self.change_selections(Default::default(), window, cx, |s| {
13157            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
13158        });
13159    }
13160
13161    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
13162        if self.take_rename(true, window, cx).is_some() {
13163            return;
13164        }
13165
13166        if self.mode.is_single_line() {
13167            cx.propagate();
13168            return;
13169        }
13170
13171        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13172
13173        let text_layout_details = &self.text_layout_details(window);
13174        let selection_count = self.selections.count();
13175        let first_selection = self.selections.first_anchor();
13176
13177        self.change_selections(Default::default(), window, cx, |s| {
13178            s.move_with(|map, selection| {
13179                if !selection.is_empty() {
13180                    selection.goal = SelectionGoal::None;
13181                }
13182                let (cursor, goal) = movement::up(
13183                    map,
13184                    selection.start,
13185                    selection.goal,
13186                    false,
13187                    text_layout_details,
13188                );
13189                selection.collapse_to(cursor, goal);
13190            });
13191        });
13192
13193        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
13194        {
13195            cx.propagate();
13196        }
13197    }
13198
13199    pub fn move_up_by_lines(
13200        &mut self,
13201        action: &MoveUpByLines,
13202        window: &mut Window,
13203        cx: &mut Context<Self>,
13204    ) {
13205        if self.take_rename(true, window, cx).is_some() {
13206            return;
13207        }
13208
13209        if self.mode.is_single_line() {
13210            cx.propagate();
13211            return;
13212        }
13213
13214        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13215
13216        let text_layout_details = &self.text_layout_details(window);
13217
13218        self.change_selections(Default::default(), window, cx, |s| {
13219            s.move_with(|map, selection| {
13220                if !selection.is_empty() {
13221                    selection.goal = SelectionGoal::None;
13222                }
13223                let (cursor, goal) = movement::up_by_rows(
13224                    map,
13225                    selection.start,
13226                    action.lines,
13227                    selection.goal,
13228                    false,
13229                    text_layout_details,
13230                );
13231                selection.collapse_to(cursor, goal);
13232            });
13233        })
13234    }
13235
13236    pub fn move_down_by_lines(
13237        &mut self,
13238        action: &MoveDownByLines,
13239        window: &mut Window,
13240        cx: &mut Context<Self>,
13241    ) {
13242        if self.take_rename(true, window, cx).is_some() {
13243            return;
13244        }
13245
13246        if self.mode.is_single_line() {
13247            cx.propagate();
13248            return;
13249        }
13250
13251        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13252
13253        let text_layout_details = &self.text_layout_details(window);
13254
13255        self.change_selections(Default::default(), window, cx, |s| {
13256            s.move_with(|map, selection| {
13257                if !selection.is_empty() {
13258                    selection.goal = SelectionGoal::None;
13259                }
13260                let (cursor, goal) = movement::down_by_rows(
13261                    map,
13262                    selection.start,
13263                    action.lines,
13264                    selection.goal,
13265                    false,
13266                    text_layout_details,
13267                );
13268                selection.collapse_to(cursor, goal);
13269            });
13270        })
13271    }
13272
13273    pub fn select_down_by_lines(
13274        &mut self,
13275        action: &SelectDownByLines,
13276        window: &mut Window,
13277        cx: &mut Context<Self>,
13278    ) {
13279        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13280        let text_layout_details = &self.text_layout_details(window);
13281        self.change_selections(Default::default(), window, cx, |s| {
13282            s.move_heads_with(|map, head, goal| {
13283                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
13284            })
13285        })
13286    }
13287
13288    pub fn select_up_by_lines(
13289        &mut self,
13290        action: &SelectUpByLines,
13291        window: &mut Window,
13292        cx: &mut Context<Self>,
13293    ) {
13294        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13295        let text_layout_details = &self.text_layout_details(window);
13296        self.change_selections(Default::default(), window, cx, |s| {
13297            s.move_heads_with(|map, head, goal| {
13298                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
13299            })
13300        })
13301    }
13302
13303    pub fn select_page_up(
13304        &mut self,
13305        _: &SelectPageUp,
13306        window: &mut Window,
13307        cx: &mut Context<Self>,
13308    ) {
13309        let Some(row_count) = self.visible_row_count() else {
13310            return;
13311        };
13312
13313        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13314
13315        let text_layout_details = &self.text_layout_details(window);
13316
13317        self.change_selections(Default::default(), window, cx, |s| {
13318            s.move_heads_with(|map, head, goal| {
13319                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
13320            })
13321        })
13322    }
13323
13324    pub fn move_page_up(
13325        &mut self,
13326        action: &MovePageUp,
13327        window: &mut Window,
13328        cx: &mut Context<Self>,
13329    ) {
13330        if self.take_rename(true, window, cx).is_some() {
13331            return;
13332        }
13333
13334        if self
13335            .context_menu
13336            .borrow_mut()
13337            .as_mut()
13338            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
13339            .unwrap_or(false)
13340        {
13341            return;
13342        }
13343
13344        if matches!(self.mode, EditorMode::SingleLine) {
13345            cx.propagate();
13346            return;
13347        }
13348
13349        let Some(row_count) = self.visible_row_count() else {
13350            return;
13351        };
13352
13353        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13354
13355        let effects = if action.center_cursor {
13356            SelectionEffects::scroll(Autoscroll::center())
13357        } else {
13358            SelectionEffects::default()
13359        };
13360
13361        let text_layout_details = &self.text_layout_details(window);
13362
13363        self.change_selections(effects, window, cx, |s| {
13364            s.move_with(|map, selection| {
13365                if !selection.is_empty() {
13366                    selection.goal = SelectionGoal::None;
13367                }
13368                let (cursor, goal) = movement::up_by_rows(
13369                    map,
13370                    selection.end,
13371                    row_count,
13372                    selection.goal,
13373                    false,
13374                    text_layout_details,
13375                );
13376                selection.collapse_to(cursor, goal);
13377            });
13378        });
13379    }
13380
13381    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
13382        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13383        let text_layout_details = &self.text_layout_details(window);
13384        self.change_selections(Default::default(), window, cx, |s| {
13385            s.move_heads_with(|map, head, goal| {
13386                movement::up(map, head, goal, false, text_layout_details)
13387            })
13388        })
13389    }
13390
13391    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
13392        self.take_rename(true, window, cx);
13393
13394        if self.mode.is_single_line() {
13395            cx.propagate();
13396            return;
13397        }
13398
13399        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13400
13401        let text_layout_details = &self.text_layout_details(window);
13402        let selection_count = self.selections.count();
13403        let first_selection = self.selections.first_anchor();
13404
13405        self.change_selections(Default::default(), window, cx, |s| {
13406            s.move_with(|map, selection| {
13407                if !selection.is_empty() {
13408                    selection.goal = SelectionGoal::None;
13409                }
13410                let (cursor, goal) = movement::down(
13411                    map,
13412                    selection.end,
13413                    selection.goal,
13414                    false,
13415                    text_layout_details,
13416                );
13417                selection.collapse_to(cursor, goal);
13418            });
13419        });
13420
13421        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
13422        {
13423            cx.propagate();
13424        }
13425    }
13426
13427    pub fn select_page_down(
13428        &mut self,
13429        _: &SelectPageDown,
13430        window: &mut Window,
13431        cx: &mut Context<Self>,
13432    ) {
13433        let Some(row_count) = self.visible_row_count() else {
13434            return;
13435        };
13436
13437        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13438
13439        let text_layout_details = &self.text_layout_details(window);
13440
13441        self.change_selections(Default::default(), window, cx, |s| {
13442            s.move_heads_with(|map, head, goal| {
13443                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
13444            })
13445        })
13446    }
13447
13448    pub fn move_page_down(
13449        &mut self,
13450        action: &MovePageDown,
13451        window: &mut Window,
13452        cx: &mut Context<Self>,
13453    ) {
13454        if self.take_rename(true, window, cx).is_some() {
13455            return;
13456        }
13457
13458        if self
13459            .context_menu
13460            .borrow_mut()
13461            .as_mut()
13462            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
13463            .unwrap_or(false)
13464        {
13465            return;
13466        }
13467
13468        if matches!(self.mode, EditorMode::SingleLine) {
13469            cx.propagate();
13470            return;
13471        }
13472
13473        let Some(row_count) = self.visible_row_count() else {
13474            return;
13475        };
13476
13477        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13478
13479        let effects = if action.center_cursor {
13480            SelectionEffects::scroll(Autoscroll::center())
13481        } else {
13482            SelectionEffects::default()
13483        };
13484
13485        let text_layout_details = &self.text_layout_details(window);
13486        self.change_selections(effects, window, cx, |s| {
13487            s.move_with(|map, selection| {
13488                if !selection.is_empty() {
13489                    selection.goal = SelectionGoal::None;
13490                }
13491                let (cursor, goal) = movement::down_by_rows(
13492                    map,
13493                    selection.end,
13494                    row_count,
13495                    selection.goal,
13496                    false,
13497                    text_layout_details,
13498                );
13499                selection.collapse_to(cursor, goal);
13500            });
13501        });
13502    }
13503
13504    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
13505        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13506        let text_layout_details = &self.text_layout_details(window);
13507        self.change_selections(Default::default(), window, cx, |s| {
13508            s.move_heads_with(|map, head, goal| {
13509                movement::down(map, head, goal, false, text_layout_details)
13510            })
13511        });
13512    }
13513
13514    pub fn context_menu_first(
13515        &mut self,
13516        _: &ContextMenuFirst,
13517        window: &mut Window,
13518        cx: &mut Context<Self>,
13519    ) {
13520        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13521            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
13522        }
13523    }
13524
13525    pub fn context_menu_prev(
13526        &mut self,
13527        _: &ContextMenuPrevious,
13528        window: &mut Window,
13529        cx: &mut Context<Self>,
13530    ) {
13531        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13532            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
13533        }
13534    }
13535
13536    pub fn context_menu_next(
13537        &mut self,
13538        _: &ContextMenuNext,
13539        window: &mut Window,
13540        cx: &mut Context<Self>,
13541    ) {
13542        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13543            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
13544        }
13545    }
13546
13547    pub fn context_menu_last(
13548        &mut self,
13549        _: &ContextMenuLast,
13550        window: &mut Window,
13551        cx: &mut Context<Self>,
13552    ) {
13553        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13554            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
13555        }
13556    }
13557
13558    pub fn signature_help_prev(
13559        &mut self,
13560        _: &SignatureHelpPrevious,
13561        _: &mut Window,
13562        cx: &mut Context<Self>,
13563    ) {
13564        if let Some(popover) = self.signature_help_state.popover_mut() {
13565            if popover.current_signature == 0 {
13566                popover.current_signature = popover.signatures.len() - 1;
13567            } else {
13568                popover.current_signature -= 1;
13569            }
13570            cx.notify();
13571        }
13572    }
13573
13574    pub fn signature_help_next(
13575        &mut self,
13576        _: &SignatureHelpNext,
13577        _: &mut Window,
13578        cx: &mut Context<Self>,
13579    ) {
13580        if let Some(popover) = self.signature_help_state.popover_mut() {
13581            if popover.current_signature + 1 == popover.signatures.len() {
13582                popover.current_signature = 0;
13583            } else {
13584                popover.current_signature += 1;
13585            }
13586            cx.notify();
13587        }
13588    }
13589
13590    pub fn move_to_previous_word_start(
13591        &mut self,
13592        _: &MoveToPreviousWordStart,
13593        window: &mut Window,
13594        cx: &mut Context<Self>,
13595    ) {
13596        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13597        self.change_selections(Default::default(), window, cx, |s| {
13598            s.move_cursors_with(|map, head, _| {
13599                (
13600                    movement::previous_word_start(map, head),
13601                    SelectionGoal::None,
13602                )
13603            });
13604        })
13605    }
13606
13607    pub fn move_to_previous_subword_start(
13608        &mut self,
13609        _: &MoveToPreviousSubwordStart,
13610        window: &mut Window,
13611        cx: &mut Context<Self>,
13612    ) {
13613        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13614        self.change_selections(Default::default(), window, cx, |s| {
13615            s.move_cursors_with(|map, head, _| {
13616                (
13617                    movement::previous_subword_start(map, head),
13618                    SelectionGoal::None,
13619                )
13620            });
13621        })
13622    }
13623
13624    pub fn select_to_previous_word_start(
13625        &mut self,
13626        _: &SelectToPreviousWordStart,
13627        window: &mut Window,
13628        cx: &mut Context<Self>,
13629    ) {
13630        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13631        self.change_selections(Default::default(), window, cx, |s| {
13632            s.move_heads_with(|map, head, _| {
13633                (
13634                    movement::previous_word_start(map, head),
13635                    SelectionGoal::None,
13636                )
13637            });
13638        })
13639    }
13640
13641    pub fn select_to_previous_subword_start(
13642        &mut self,
13643        _: &SelectToPreviousSubwordStart,
13644        window: &mut Window,
13645        cx: &mut Context<Self>,
13646    ) {
13647        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13648        self.change_selections(Default::default(), window, cx, |s| {
13649            s.move_heads_with(|map, head, _| {
13650                (
13651                    movement::previous_subword_start(map, head),
13652                    SelectionGoal::None,
13653                )
13654            });
13655        })
13656    }
13657
13658    pub fn delete_to_previous_word_start(
13659        &mut self,
13660        action: &DeleteToPreviousWordStart,
13661        window: &mut Window,
13662        cx: &mut Context<Self>,
13663    ) {
13664        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13665        self.transact(window, cx, |this, window, cx| {
13666            this.select_autoclose_pair(window, cx);
13667            this.change_selections(Default::default(), window, cx, |s| {
13668                s.move_with(|map, selection| {
13669                    if selection.is_empty() {
13670                        let mut cursor = if action.ignore_newlines {
13671                            movement::previous_word_start(map, selection.head())
13672                        } else {
13673                            movement::previous_word_start_or_newline(map, selection.head())
13674                        };
13675                        cursor = movement::adjust_greedy_deletion(
13676                            map,
13677                            selection.head(),
13678                            cursor,
13679                            action.ignore_brackets,
13680                        );
13681                        selection.set_head(cursor, SelectionGoal::None);
13682                    }
13683                });
13684            });
13685            this.insert("", window, cx);
13686        });
13687    }
13688
13689    pub fn delete_to_previous_subword_start(
13690        &mut self,
13691        _: &DeleteToPreviousSubwordStart,
13692        window: &mut Window,
13693        cx: &mut Context<Self>,
13694    ) {
13695        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13696        self.transact(window, cx, |this, window, cx| {
13697            this.select_autoclose_pair(window, cx);
13698            this.change_selections(Default::default(), window, cx, |s| {
13699                s.move_with(|map, selection| {
13700                    if selection.is_empty() {
13701                        let mut cursor = movement::previous_subword_start(map, selection.head());
13702                        cursor =
13703                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13704                        selection.set_head(cursor, SelectionGoal::None);
13705                    }
13706                });
13707            });
13708            this.insert("", window, cx);
13709        });
13710    }
13711
13712    pub fn move_to_next_word_end(
13713        &mut self,
13714        _: &MoveToNextWordEnd,
13715        window: &mut Window,
13716        cx: &mut Context<Self>,
13717    ) {
13718        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13719        self.change_selections(Default::default(), window, cx, |s| {
13720            s.move_cursors_with(|map, head, _| {
13721                (movement::next_word_end(map, head), SelectionGoal::None)
13722            });
13723        })
13724    }
13725
13726    pub fn move_to_next_subword_end(
13727        &mut self,
13728        _: &MoveToNextSubwordEnd,
13729        window: &mut Window,
13730        cx: &mut Context<Self>,
13731    ) {
13732        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13733        self.change_selections(Default::default(), window, cx, |s| {
13734            s.move_cursors_with(|map, head, _| {
13735                (movement::next_subword_end(map, head), SelectionGoal::None)
13736            });
13737        })
13738    }
13739
13740    pub fn select_to_next_word_end(
13741        &mut self,
13742        _: &SelectToNextWordEnd,
13743        window: &mut Window,
13744        cx: &mut Context<Self>,
13745    ) {
13746        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13747        self.change_selections(Default::default(), window, cx, |s| {
13748            s.move_heads_with(|map, head, _| {
13749                (movement::next_word_end(map, head), SelectionGoal::None)
13750            });
13751        })
13752    }
13753
13754    pub fn select_to_next_subword_end(
13755        &mut self,
13756        _: &SelectToNextSubwordEnd,
13757        window: &mut Window,
13758        cx: &mut Context<Self>,
13759    ) {
13760        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13761        self.change_selections(Default::default(), window, cx, |s| {
13762            s.move_heads_with(|map, head, _| {
13763                (movement::next_subword_end(map, head), SelectionGoal::None)
13764            });
13765        })
13766    }
13767
13768    pub fn delete_to_next_word_end(
13769        &mut self,
13770        action: &DeleteToNextWordEnd,
13771        window: &mut Window,
13772        cx: &mut Context<Self>,
13773    ) {
13774        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13775        self.transact(window, cx, |this, window, cx| {
13776            this.change_selections(Default::default(), window, cx, |s| {
13777                s.move_with(|map, selection| {
13778                    if selection.is_empty() {
13779                        let mut cursor = if action.ignore_newlines {
13780                            movement::next_word_end(map, selection.head())
13781                        } else {
13782                            movement::next_word_end_or_newline(map, selection.head())
13783                        };
13784                        cursor = movement::adjust_greedy_deletion(
13785                            map,
13786                            selection.head(),
13787                            cursor,
13788                            action.ignore_brackets,
13789                        );
13790                        selection.set_head(cursor, SelectionGoal::None);
13791                    }
13792                });
13793            });
13794            this.insert("", window, cx);
13795        });
13796    }
13797
13798    pub fn delete_to_next_subword_end(
13799        &mut self,
13800        _: &DeleteToNextSubwordEnd,
13801        window: &mut Window,
13802        cx: &mut Context<Self>,
13803    ) {
13804        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13805        self.transact(window, cx, |this, window, cx| {
13806            this.change_selections(Default::default(), window, cx, |s| {
13807                s.move_with(|map, selection| {
13808                    if selection.is_empty() {
13809                        let mut cursor = movement::next_subword_end(map, selection.head());
13810                        cursor =
13811                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13812                        selection.set_head(cursor, SelectionGoal::None);
13813                    }
13814                });
13815            });
13816            this.insert("", window, cx);
13817        });
13818    }
13819
13820    pub fn move_to_beginning_of_line(
13821        &mut self,
13822        action: &MoveToBeginningOfLine,
13823        window: &mut Window,
13824        cx: &mut Context<Self>,
13825    ) {
13826        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13827        self.change_selections(Default::default(), window, cx, |s| {
13828            s.move_cursors_with(|map, head, _| {
13829                (
13830                    movement::indented_line_beginning(
13831                        map,
13832                        head,
13833                        action.stop_at_soft_wraps,
13834                        action.stop_at_indent,
13835                    ),
13836                    SelectionGoal::None,
13837                )
13838            });
13839        })
13840    }
13841
13842    pub fn select_to_beginning_of_line(
13843        &mut self,
13844        action: &SelectToBeginningOfLine,
13845        window: &mut Window,
13846        cx: &mut Context<Self>,
13847    ) {
13848        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13849        self.change_selections(Default::default(), window, cx, |s| {
13850            s.move_heads_with(|map, head, _| {
13851                (
13852                    movement::indented_line_beginning(
13853                        map,
13854                        head,
13855                        action.stop_at_soft_wraps,
13856                        action.stop_at_indent,
13857                    ),
13858                    SelectionGoal::None,
13859                )
13860            });
13861        });
13862    }
13863
13864    pub fn delete_to_beginning_of_line(
13865        &mut self,
13866        action: &DeleteToBeginningOfLine,
13867        window: &mut Window,
13868        cx: &mut Context<Self>,
13869    ) {
13870        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13871        self.transact(window, cx, |this, window, cx| {
13872            this.change_selections(Default::default(), window, cx, |s| {
13873                s.move_with(|_, selection| {
13874                    selection.reversed = true;
13875                });
13876            });
13877
13878            this.select_to_beginning_of_line(
13879                &SelectToBeginningOfLine {
13880                    stop_at_soft_wraps: false,
13881                    stop_at_indent: action.stop_at_indent,
13882                },
13883                window,
13884                cx,
13885            );
13886            this.backspace(&Backspace, window, cx);
13887        });
13888    }
13889
13890    pub fn move_to_end_of_line(
13891        &mut self,
13892        action: &MoveToEndOfLine,
13893        window: &mut Window,
13894        cx: &mut Context<Self>,
13895    ) {
13896        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13897        self.change_selections(Default::default(), window, cx, |s| {
13898            s.move_cursors_with(|map, head, _| {
13899                (
13900                    movement::line_end(map, head, action.stop_at_soft_wraps),
13901                    SelectionGoal::None,
13902                )
13903            });
13904        })
13905    }
13906
13907    pub fn select_to_end_of_line(
13908        &mut self,
13909        action: &SelectToEndOfLine,
13910        window: &mut Window,
13911        cx: &mut Context<Self>,
13912    ) {
13913        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13914        self.change_selections(Default::default(), window, cx, |s| {
13915            s.move_heads_with(|map, head, _| {
13916                (
13917                    movement::line_end(map, head, action.stop_at_soft_wraps),
13918                    SelectionGoal::None,
13919                )
13920            });
13921        })
13922    }
13923
13924    pub fn delete_to_end_of_line(
13925        &mut self,
13926        _: &DeleteToEndOfLine,
13927        window: &mut Window,
13928        cx: &mut Context<Self>,
13929    ) {
13930        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13931        self.transact(window, cx, |this, window, cx| {
13932            this.select_to_end_of_line(
13933                &SelectToEndOfLine {
13934                    stop_at_soft_wraps: false,
13935                },
13936                window,
13937                cx,
13938            );
13939            this.delete(&Delete, window, cx);
13940        });
13941    }
13942
13943    pub fn cut_to_end_of_line(
13944        &mut self,
13945        action: &CutToEndOfLine,
13946        window: &mut Window,
13947        cx: &mut Context<Self>,
13948    ) {
13949        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13950        self.transact(window, cx, |this, window, cx| {
13951            this.select_to_end_of_line(
13952                &SelectToEndOfLine {
13953                    stop_at_soft_wraps: false,
13954                },
13955                window,
13956                cx,
13957            );
13958            if !action.stop_at_newlines {
13959                this.change_selections(Default::default(), window, cx, |s| {
13960                    s.move_with(|_, sel| {
13961                        if sel.is_empty() {
13962                            sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
13963                        }
13964                    });
13965                });
13966            }
13967            this.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13968            let item = this.cut_common(false, window, cx);
13969            cx.write_to_clipboard(item);
13970        });
13971    }
13972
13973    pub fn move_to_start_of_paragraph(
13974        &mut self,
13975        _: &MoveToStartOfParagraph,
13976        window: &mut Window,
13977        cx: &mut Context<Self>,
13978    ) {
13979        if matches!(self.mode, EditorMode::SingleLine) {
13980            cx.propagate();
13981            return;
13982        }
13983        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13984        self.change_selections(Default::default(), window, cx, |s| {
13985            s.move_with(|map, selection| {
13986                selection.collapse_to(
13987                    movement::start_of_paragraph(map, selection.head(), 1),
13988                    SelectionGoal::None,
13989                )
13990            });
13991        })
13992    }
13993
13994    pub fn move_to_end_of_paragraph(
13995        &mut self,
13996        _: &MoveToEndOfParagraph,
13997        window: &mut Window,
13998        cx: &mut Context<Self>,
13999    ) {
14000        if matches!(self.mode, EditorMode::SingleLine) {
14001            cx.propagate();
14002            return;
14003        }
14004        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14005        self.change_selections(Default::default(), window, cx, |s| {
14006            s.move_with(|map, selection| {
14007                selection.collapse_to(
14008                    movement::end_of_paragraph(map, selection.head(), 1),
14009                    SelectionGoal::None,
14010                )
14011            });
14012        })
14013    }
14014
14015    pub fn select_to_start_of_paragraph(
14016        &mut self,
14017        _: &SelectToStartOfParagraph,
14018        window: &mut Window,
14019        cx: &mut Context<Self>,
14020    ) {
14021        if matches!(self.mode, EditorMode::SingleLine) {
14022            cx.propagate();
14023            return;
14024        }
14025        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14026        self.change_selections(Default::default(), window, cx, |s| {
14027            s.move_heads_with(|map, head, _| {
14028                (
14029                    movement::start_of_paragraph(map, head, 1),
14030                    SelectionGoal::None,
14031                )
14032            });
14033        })
14034    }
14035
14036    pub fn select_to_end_of_paragraph(
14037        &mut self,
14038        _: &SelectToEndOfParagraph,
14039        window: &mut Window,
14040        cx: &mut Context<Self>,
14041    ) {
14042        if matches!(self.mode, EditorMode::SingleLine) {
14043            cx.propagate();
14044            return;
14045        }
14046        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14047        self.change_selections(Default::default(), window, cx, |s| {
14048            s.move_heads_with(|map, head, _| {
14049                (
14050                    movement::end_of_paragraph(map, head, 1),
14051                    SelectionGoal::None,
14052                )
14053            });
14054        })
14055    }
14056
14057    pub fn move_to_start_of_excerpt(
14058        &mut self,
14059        _: &MoveToStartOfExcerpt,
14060        window: &mut Window,
14061        cx: &mut Context<Self>,
14062    ) {
14063        if matches!(self.mode, EditorMode::SingleLine) {
14064            cx.propagate();
14065            return;
14066        }
14067        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14068        self.change_selections(Default::default(), window, cx, |s| {
14069            s.move_with(|map, selection| {
14070                selection.collapse_to(
14071                    movement::start_of_excerpt(
14072                        map,
14073                        selection.head(),
14074                        workspace::searchable::Direction::Prev,
14075                    ),
14076                    SelectionGoal::None,
14077                )
14078            });
14079        })
14080    }
14081
14082    pub fn move_to_start_of_next_excerpt(
14083        &mut self,
14084        _: &MoveToStartOfNextExcerpt,
14085        window: &mut Window,
14086        cx: &mut Context<Self>,
14087    ) {
14088        if matches!(self.mode, EditorMode::SingleLine) {
14089            cx.propagate();
14090            return;
14091        }
14092
14093        self.change_selections(Default::default(), window, cx, |s| {
14094            s.move_with(|map, selection| {
14095                selection.collapse_to(
14096                    movement::start_of_excerpt(
14097                        map,
14098                        selection.head(),
14099                        workspace::searchable::Direction::Next,
14100                    ),
14101                    SelectionGoal::None,
14102                )
14103            });
14104        })
14105    }
14106
14107    pub fn move_to_end_of_excerpt(
14108        &mut self,
14109        _: &MoveToEndOfExcerpt,
14110        window: &mut Window,
14111        cx: &mut Context<Self>,
14112    ) {
14113        if matches!(self.mode, EditorMode::SingleLine) {
14114            cx.propagate();
14115            return;
14116        }
14117        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14118        self.change_selections(Default::default(), window, cx, |s| {
14119            s.move_with(|map, selection| {
14120                selection.collapse_to(
14121                    movement::end_of_excerpt(
14122                        map,
14123                        selection.head(),
14124                        workspace::searchable::Direction::Next,
14125                    ),
14126                    SelectionGoal::None,
14127                )
14128            });
14129        })
14130    }
14131
14132    pub fn move_to_end_of_previous_excerpt(
14133        &mut self,
14134        _: &MoveToEndOfPreviousExcerpt,
14135        window: &mut Window,
14136        cx: &mut Context<Self>,
14137    ) {
14138        if matches!(self.mode, EditorMode::SingleLine) {
14139            cx.propagate();
14140            return;
14141        }
14142        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14143        self.change_selections(Default::default(), window, cx, |s| {
14144            s.move_with(|map, selection| {
14145                selection.collapse_to(
14146                    movement::end_of_excerpt(
14147                        map,
14148                        selection.head(),
14149                        workspace::searchable::Direction::Prev,
14150                    ),
14151                    SelectionGoal::None,
14152                )
14153            });
14154        })
14155    }
14156
14157    pub fn select_to_start_of_excerpt(
14158        &mut self,
14159        _: &SelectToStartOfExcerpt,
14160        window: &mut Window,
14161        cx: &mut Context<Self>,
14162    ) {
14163        if matches!(self.mode, EditorMode::SingleLine) {
14164            cx.propagate();
14165            return;
14166        }
14167        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14168        self.change_selections(Default::default(), window, cx, |s| {
14169            s.move_heads_with(|map, head, _| {
14170                (
14171                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
14172                    SelectionGoal::None,
14173                )
14174            });
14175        })
14176    }
14177
14178    pub fn select_to_start_of_next_excerpt(
14179        &mut self,
14180        _: &SelectToStartOfNextExcerpt,
14181        window: &mut Window,
14182        cx: &mut Context<Self>,
14183    ) {
14184        if matches!(self.mode, EditorMode::SingleLine) {
14185            cx.propagate();
14186            return;
14187        }
14188        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14189        self.change_selections(Default::default(), window, cx, |s| {
14190            s.move_heads_with(|map, head, _| {
14191                (
14192                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
14193                    SelectionGoal::None,
14194                )
14195            });
14196        })
14197    }
14198
14199    pub fn select_to_end_of_excerpt(
14200        &mut self,
14201        _: &SelectToEndOfExcerpt,
14202        window: &mut Window,
14203        cx: &mut Context<Self>,
14204    ) {
14205        if matches!(self.mode, EditorMode::SingleLine) {
14206            cx.propagate();
14207            return;
14208        }
14209        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14210        self.change_selections(Default::default(), window, cx, |s| {
14211            s.move_heads_with(|map, head, _| {
14212                (
14213                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
14214                    SelectionGoal::None,
14215                )
14216            });
14217        })
14218    }
14219
14220    pub fn select_to_end_of_previous_excerpt(
14221        &mut self,
14222        _: &SelectToEndOfPreviousExcerpt,
14223        window: &mut Window,
14224        cx: &mut Context<Self>,
14225    ) {
14226        if matches!(self.mode, EditorMode::SingleLine) {
14227            cx.propagate();
14228            return;
14229        }
14230        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14231        self.change_selections(Default::default(), window, cx, |s| {
14232            s.move_heads_with(|map, head, _| {
14233                (
14234                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
14235                    SelectionGoal::None,
14236                )
14237            });
14238        })
14239    }
14240
14241    pub fn move_to_beginning(
14242        &mut self,
14243        _: &MoveToBeginning,
14244        window: &mut Window,
14245        cx: &mut Context<Self>,
14246    ) {
14247        if matches!(self.mode, EditorMode::SingleLine) {
14248            cx.propagate();
14249            return;
14250        }
14251        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14252        self.change_selections(Default::default(), window, cx, |s| {
14253            s.select_ranges(vec![Anchor::min()..Anchor::min()]);
14254        });
14255    }
14256
14257    pub fn select_to_beginning(
14258        &mut self,
14259        _: &SelectToBeginning,
14260        window: &mut Window,
14261        cx: &mut Context<Self>,
14262    ) {
14263        let mut selection = self.selections.last::<Point>(&self.display_snapshot(cx));
14264        selection.set_head(Point::zero(), SelectionGoal::None);
14265        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14266        self.change_selections(Default::default(), window, cx, |s| {
14267            s.select(vec![selection]);
14268        });
14269    }
14270
14271    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
14272        if matches!(self.mode, EditorMode::SingleLine) {
14273            cx.propagate();
14274            return;
14275        }
14276        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14277        let cursor = self.buffer.read(cx).read(cx).len();
14278        self.change_selections(Default::default(), window, cx, |s| {
14279            s.select_ranges(vec![cursor..cursor])
14280        });
14281    }
14282
14283    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
14284        self.nav_history = nav_history;
14285    }
14286
14287    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
14288        self.nav_history.as_ref()
14289    }
14290
14291    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
14292        self.push_to_nav_history(
14293            self.selections.newest_anchor().head(),
14294            None,
14295            false,
14296            true,
14297            cx,
14298        );
14299    }
14300
14301    fn push_to_nav_history(
14302        &mut self,
14303        cursor_anchor: Anchor,
14304        new_position: Option<Point>,
14305        is_deactivate: bool,
14306        always: bool,
14307        cx: &mut Context<Self>,
14308    ) {
14309        if let Some(nav_history) = self.nav_history.as_mut() {
14310            let buffer = self.buffer.read(cx).read(cx);
14311            let cursor_position = cursor_anchor.to_point(&buffer);
14312            let scroll_state = self.scroll_manager.anchor();
14313            let scroll_top_row = scroll_state.top_row(&buffer);
14314            drop(buffer);
14315
14316            if let Some(new_position) = new_position {
14317                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
14318                if row_delta == 0 || (row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA && !always) {
14319                    return;
14320                }
14321            }
14322
14323            nav_history.push(
14324                Some(NavigationData {
14325                    cursor_anchor,
14326                    cursor_position,
14327                    scroll_anchor: scroll_state,
14328                    scroll_top_row,
14329                }),
14330                cx,
14331            );
14332            cx.emit(EditorEvent::PushedToNavHistory {
14333                anchor: cursor_anchor,
14334                is_deactivate,
14335            })
14336        }
14337    }
14338
14339    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
14340        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14341        let buffer = self.buffer.read(cx).snapshot(cx);
14342        let mut selection = self
14343            .selections
14344            .first::<MultiBufferOffset>(&self.display_snapshot(cx));
14345        selection.set_head(buffer.len(), SelectionGoal::None);
14346        self.change_selections(Default::default(), window, cx, |s| {
14347            s.select(vec![selection]);
14348        });
14349    }
14350
14351    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
14352        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14353        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14354            s.select_ranges(vec![Anchor::min()..Anchor::max()]);
14355        });
14356    }
14357
14358    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
14359        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14360        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14361        let mut selections = self.selections.all::<Point>(&display_map);
14362        let max_point = display_map.buffer_snapshot().max_point();
14363        for selection in &mut selections {
14364            let rows = selection.spanned_rows(true, &display_map);
14365            selection.start = Point::new(rows.start.0, 0);
14366            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
14367            selection.reversed = false;
14368        }
14369        self.change_selections(Default::default(), window, cx, |s| {
14370            s.select(selections);
14371        });
14372    }
14373
14374    pub fn split_selection_into_lines(
14375        &mut self,
14376        action: &SplitSelectionIntoLines,
14377        window: &mut Window,
14378        cx: &mut Context<Self>,
14379    ) {
14380        let selections = self
14381            .selections
14382            .all::<Point>(&self.display_snapshot(cx))
14383            .into_iter()
14384            .map(|selection| selection.start..selection.end)
14385            .collect::<Vec<_>>();
14386        self.unfold_ranges(&selections, true, true, cx);
14387
14388        let mut new_selection_ranges = Vec::new();
14389        {
14390            let buffer = self.buffer.read(cx).read(cx);
14391            for selection in selections {
14392                for row in selection.start.row..selection.end.row {
14393                    let line_start = Point::new(row, 0);
14394                    let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
14395
14396                    if action.keep_selections {
14397                        // Keep the selection range for each line
14398                        let selection_start = if row == selection.start.row {
14399                            selection.start
14400                        } else {
14401                            line_start
14402                        };
14403                        new_selection_ranges.push(selection_start..line_end);
14404                    } else {
14405                        // Collapse to cursor at end of line
14406                        new_selection_ranges.push(line_end..line_end);
14407                    }
14408                }
14409
14410                let is_multiline_selection = selection.start.row != selection.end.row;
14411                // Don't insert last one if it's a multi-line selection ending at the start of a line,
14412                // so this action feels more ergonomic when paired with other selection operations
14413                let should_skip_last = is_multiline_selection && selection.end.column == 0;
14414                if !should_skip_last {
14415                    if action.keep_selections {
14416                        if is_multiline_selection {
14417                            let line_start = Point::new(selection.end.row, 0);
14418                            new_selection_ranges.push(line_start..selection.end);
14419                        } else {
14420                            new_selection_ranges.push(selection.start..selection.end);
14421                        }
14422                    } else {
14423                        new_selection_ranges.push(selection.end..selection.end);
14424                    }
14425                }
14426            }
14427        }
14428        self.change_selections(Default::default(), window, cx, |s| {
14429            s.select_ranges(new_selection_ranges);
14430        });
14431    }
14432
14433    pub fn add_selection_above(
14434        &mut self,
14435        action: &AddSelectionAbove,
14436        window: &mut Window,
14437        cx: &mut Context<Self>,
14438    ) {
14439        self.add_selection(true, action.skip_soft_wrap, window, cx);
14440    }
14441
14442    pub fn add_selection_below(
14443        &mut self,
14444        action: &AddSelectionBelow,
14445        window: &mut Window,
14446        cx: &mut Context<Self>,
14447    ) {
14448        self.add_selection(false, action.skip_soft_wrap, window, cx);
14449    }
14450
14451    fn add_selection(
14452        &mut self,
14453        above: bool,
14454        skip_soft_wrap: bool,
14455        window: &mut Window,
14456        cx: &mut Context<Self>,
14457    ) {
14458        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14459
14460        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14461        let all_selections = self.selections.all::<Point>(&display_map);
14462        let text_layout_details = self.text_layout_details(window);
14463
14464        let (mut columnar_selections, new_selections_to_columnarize) = {
14465            if let Some(state) = self.add_selections_state.as_ref() {
14466                let columnar_selection_ids: HashSet<_> = state
14467                    .groups
14468                    .iter()
14469                    .flat_map(|group| group.stack.iter())
14470                    .copied()
14471                    .collect();
14472
14473                all_selections
14474                    .into_iter()
14475                    .partition(|s| columnar_selection_ids.contains(&s.id))
14476            } else {
14477                (Vec::new(), all_selections)
14478            }
14479        };
14480
14481        let mut state = self
14482            .add_selections_state
14483            .take()
14484            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
14485
14486        for selection in new_selections_to_columnarize {
14487            let range = selection.display_range(&display_map).sorted();
14488            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
14489            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
14490            let positions = start_x.min(end_x)..start_x.max(end_x);
14491            let mut stack = Vec::new();
14492            for row in range.start.row().0..=range.end.row().0 {
14493                if let Some(selection) = self.selections.build_columnar_selection(
14494                    &display_map,
14495                    DisplayRow(row),
14496                    &positions,
14497                    selection.reversed,
14498                    &text_layout_details,
14499                ) {
14500                    stack.push(selection.id);
14501                    columnar_selections.push(selection);
14502                }
14503            }
14504            if !stack.is_empty() {
14505                if above {
14506                    stack.reverse();
14507                }
14508                state.groups.push(AddSelectionsGroup { above, stack });
14509            }
14510        }
14511
14512        let mut final_selections = Vec::new();
14513        let end_row = if above {
14514            DisplayRow(0)
14515        } else {
14516            display_map.max_point().row()
14517        };
14518
14519        let mut last_added_item_per_group = HashMap::default();
14520        for group in state.groups.iter_mut() {
14521            if let Some(last_id) = group.stack.last() {
14522                last_added_item_per_group.insert(*last_id, group);
14523            }
14524        }
14525
14526        for selection in columnar_selections {
14527            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
14528                if above == group.above {
14529                    let range = selection.display_range(&display_map).sorted();
14530                    debug_assert_eq!(range.start.row(), range.end.row());
14531                    let mut row = range.start.row();
14532                    let positions =
14533                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
14534                            Pixels::from(start)..Pixels::from(end)
14535                        } else {
14536                            let start_x =
14537                                display_map.x_for_display_point(range.start, &text_layout_details);
14538                            let end_x =
14539                                display_map.x_for_display_point(range.end, &text_layout_details);
14540                            start_x.min(end_x)..start_x.max(end_x)
14541                        };
14542
14543                    let mut maybe_new_selection = None;
14544                    let direction = if above { -1 } else { 1 };
14545
14546                    while row != end_row {
14547                        if skip_soft_wrap {
14548                            row = display_map
14549                                .start_of_relative_buffer_row(DisplayPoint::new(row, 0), direction)
14550                                .row();
14551                        } else if above {
14552                            row.0 -= 1;
14553                        } else {
14554                            row.0 += 1;
14555                        }
14556
14557                        if let Some(new_selection) = self.selections.build_columnar_selection(
14558                            &display_map,
14559                            row,
14560                            &positions,
14561                            selection.reversed,
14562                            &text_layout_details,
14563                        ) {
14564                            maybe_new_selection = Some(new_selection);
14565                            break;
14566                        }
14567                    }
14568
14569                    if let Some(new_selection) = maybe_new_selection {
14570                        group.stack.push(new_selection.id);
14571                        if above {
14572                            final_selections.push(new_selection);
14573                            final_selections.push(selection);
14574                        } else {
14575                            final_selections.push(selection);
14576                            final_selections.push(new_selection);
14577                        }
14578                    } else {
14579                        final_selections.push(selection);
14580                    }
14581                } else {
14582                    group.stack.pop();
14583                }
14584            } else {
14585                final_selections.push(selection);
14586            }
14587        }
14588
14589        self.change_selections(Default::default(), window, cx, |s| {
14590            s.select(final_selections);
14591        });
14592
14593        let final_selection_ids: HashSet<_> = self
14594            .selections
14595            .all::<Point>(&display_map)
14596            .iter()
14597            .map(|s| s.id)
14598            .collect();
14599        state.groups.retain_mut(|group| {
14600            // selections might get merged above so we remove invalid items from stacks
14601            group.stack.retain(|id| final_selection_ids.contains(id));
14602
14603            // single selection in stack can be treated as initial state
14604            group.stack.len() > 1
14605        });
14606
14607        if !state.groups.is_empty() {
14608            self.add_selections_state = Some(state);
14609        }
14610    }
14611
14612    fn select_match_ranges(
14613        &mut self,
14614        range: Range<MultiBufferOffset>,
14615        reversed: bool,
14616        replace_newest: bool,
14617        auto_scroll: Option<Autoscroll>,
14618        window: &mut Window,
14619        cx: &mut Context<Editor>,
14620    ) {
14621        self.unfold_ranges(
14622            std::slice::from_ref(&range),
14623            false,
14624            auto_scroll.is_some(),
14625            cx,
14626        );
14627        let effects = if let Some(scroll) = auto_scroll {
14628            SelectionEffects::scroll(scroll)
14629        } else {
14630            SelectionEffects::no_scroll()
14631        };
14632        self.change_selections(effects, window, cx, |s| {
14633            if replace_newest {
14634                s.delete(s.newest_anchor().id);
14635            }
14636            if reversed {
14637                s.insert_range(range.end..range.start);
14638            } else {
14639                s.insert_range(range);
14640            }
14641        });
14642    }
14643
14644    pub fn select_next_match_internal(
14645        &mut self,
14646        display_map: &DisplaySnapshot,
14647        replace_newest: bool,
14648        autoscroll: Option<Autoscroll>,
14649        window: &mut Window,
14650        cx: &mut Context<Self>,
14651    ) -> Result<()> {
14652        let buffer = display_map.buffer_snapshot();
14653        let mut selections = self.selections.all::<MultiBufferOffset>(&display_map);
14654        if let Some(mut select_next_state) = self.select_next_state.take() {
14655            let query = &select_next_state.query;
14656            if !select_next_state.done {
14657                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14658                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14659                let mut next_selected_range = None;
14660
14661                let bytes_after_last_selection =
14662                    buffer.bytes_in_range(last_selection.end..buffer.len());
14663                let bytes_before_first_selection =
14664                    buffer.bytes_in_range(MultiBufferOffset(0)..first_selection.start);
14665                let query_matches = query
14666                    .stream_find_iter(bytes_after_last_selection)
14667                    .map(|result| (last_selection.end, result))
14668                    .chain(
14669                        query
14670                            .stream_find_iter(bytes_before_first_selection)
14671                            .map(|result| (MultiBufferOffset(0), result)),
14672                    );
14673
14674                for (start_offset, query_match) in query_matches {
14675                    let query_match = query_match.unwrap(); // can only fail due to I/O
14676                    let offset_range =
14677                        start_offset + query_match.start()..start_offset + query_match.end();
14678
14679                    if !select_next_state.wordwise
14680                        || (!buffer.is_inside_word(offset_range.start, None)
14681                            && !buffer.is_inside_word(offset_range.end, None))
14682                    {
14683                        let idx = selections
14684                            .partition_point(|selection| selection.end <= offset_range.start);
14685                        let overlaps = selections
14686                            .get(idx)
14687                            .map_or(false, |selection| selection.start < offset_range.end);
14688
14689                        if !overlaps {
14690                            next_selected_range = Some(offset_range);
14691                            break;
14692                        }
14693                    }
14694                }
14695
14696                if let Some(next_selected_range) = next_selected_range {
14697                    self.select_match_ranges(
14698                        next_selected_range,
14699                        last_selection.reversed,
14700                        replace_newest,
14701                        autoscroll,
14702                        window,
14703                        cx,
14704                    );
14705                } else {
14706                    select_next_state.done = true;
14707                }
14708            }
14709
14710            self.select_next_state = Some(select_next_state);
14711        } else {
14712            let mut only_carets = true;
14713            let mut same_text_selected = true;
14714            let mut selected_text = None;
14715
14716            let mut selections_iter = selections.iter().peekable();
14717            while let Some(selection) = selections_iter.next() {
14718                if selection.start != selection.end {
14719                    only_carets = false;
14720                }
14721
14722                if same_text_selected {
14723                    if selected_text.is_none() {
14724                        selected_text =
14725                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14726                    }
14727
14728                    if let Some(next_selection) = selections_iter.peek() {
14729                        if next_selection.len() == selection.len() {
14730                            let next_selected_text = buffer
14731                                .text_for_range(next_selection.range())
14732                                .collect::<String>();
14733                            if Some(next_selected_text) != selected_text {
14734                                same_text_selected = false;
14735                                selected_text = None;
14736                            }
14737                        } else {
14738                            same_text_selected = false;
14739                            selected_text = None;
14740                        }
14741                    }
14742                }
14743            }
14744
14745            if only_carets {
14746                for selection in &mut selections {
14747                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
14748                    selection.start = word_range.start;
14749                    selection.end = word_range.end;
14750                    selection.goal = SelectionGoal::None;
14751                    selection.reversed = false;
14752                    self.select_match_ranges(
14753                        selection.start..selection.end,
14754                        selection.reversed,
14755                        replace_newest,
14756                        autoscroll,
14757                        window,
14758                        cx,
14759                    );
14760                }
14761
14762                if selections.len() == 1 {
14763                    let selection = selections
14764                        .last()
14765                        .expect("ensured that there's only one selection");
14766                    let query = buffer
14767                        .text_for_range(selection.start..selection.end)
14768                        .collect::<String>();
14769                    let is_empty = query.is_empty();
14770                    let select_state = SelectNextState {
14771                        query: self.build_query(&[query], cx)?,
14772                        wordwise: true,
14773                        done: is_empty,
14774                    };
14775                    self.select_next_state = Some(select_state);
14776                } else {
14777                    self.select_next_state = None;
14778                }
14779            } else if let Some(selected_text) = selected_text {
14780                self.select_next_state = Some(SelectNextState {
14781                    query: self.build_query(&[selected_text], cx)?,
14782                    wordwise: false,
14783                    done: false,
14784                });
14785                self.select_next_match_internal(
14786                    display_map,
14787                    replace_newest,
14788                    autoscroll,
14789                    window,
14790                    cx,
14791                )?;
14792            }
14793        }
14794        Ok(())
14795    }
14796
14797    pub fn select_all_matches(
14798        &mut self,
14799        _action: &SelectAllMatches,
14800        window: &mut Window,
14801        cx: &mut Context<Self>,
14802    ) -> Result<()> {
14803        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14804
14805        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14806
14807        self.select_next_match_internal(&display_map, false, None, window, cx)?;
14808        let Some(select_next_state) = self.select_next_state.as_mut() else {
14809            return Ok(());
14810        };
14811        if select_next_state.done {
14812            return Ok(());
14813        }
14814
14815        let mut new_selections = Vec::new();
14816
14817        let reversed = self
14818            .selections
14819            .oldest::<MultiBufferOffset>(&display_map)
14820            .reversed;
14821        let buffer = display_map.buffer_snapshot();
14822        let query_matches = select_next_state
14823            .query
14824            .stream_find_iter(buffer.bytes_in_range(MultiBufferOffset(0)..buffer.len()));
14825
14826        for query_match in query_matches.into_iter() {
14827            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
14828            let offset_range = if reversed {
14829                MultiBufferOffset(query_match.end())..MultiBufferOffset(query_match.start())
14830            } else {
14831                MultiBufferOffset(query_match.start())..MultiBufferOffset(query_match.end())
14832            };
14833
14834            if !select_next_state.wordwise
14835                || (!buffer.is_inside_word(offset_range.start, None)
14836                    && !buffer.is_inside_word(offset_range.end, None))
14837            {
14838                new_selections.push(offset_range.start..offset_range.end);
14839            }
14840        }
14841
14842        select_next_state.done = true;
14843
14844        if new_selections.is_empty() {
14845            log::error!("bug: new_selections is empty in select_all_matches");
14846            return Ok(());
14847        }
14848
14849        self.unfold_ranges(&new_selections.clone(), false, false, cx);
14850        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
14851            selections.select_ranges(new_selections)
14852        });
14853
14854        Ok(())
14855    }
14856
14857    pub fn select_next(
14858        &mut self,
14859        action: &SelectNext,
14860        window: &mut Window,
14861        cx: &mut Context<Self>,
14862    ) -> Result<()> {
14863        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14864        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14865        self.select_next_match_internal(
14866            &display_map,
14867            action.replace_newest,
14868            Some(Autoscroll::newest()),
14869            window,
14870            cx,
14871        )?;
14872        Ok(())
14873    }
14874
14875    pub fn select_previous(
14876        &mut self,
14877        action: &SelectPrevious,
14878        window: &mut Window,
14879        cx: &mut Context<Self>,
14880    ) -> Result<()> {
14881        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14882        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14883        let buffer = display_map.buffer_snapshot();
14884        let mut selections = self.selections.all::<MultiBufferOffset>(&display_map);
14885        if let Some(mut select_prev_state) = self.select_prev_state.take() {
14886            let query = &select_prev_state.query;
14887            if !select_prev_state.done {
14888                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14889                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14890                let mut next_selected_range = None;
14891                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
14892                let bytes_before_last_selection =
14893                    buffer.reversed_bytes_in_range(MultiBufferOffset(0)..last_selection.start);
14894                let bytes_after_first_selection =
14895                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
14896                let query_matches = query
14897                    .stream_find_iter(bytes_before_last_selection)
14898                    .map(|result| (last_selection.start, result))
14899                    .chain(
14900                        query
14901                            .stream_find_iter(bytes_after_first_selection)
14902                            .map(|result| (buffer.len(), result)),
14903                    );
14904                for (end_offset, query_match) in query_matches {
14905                    let query_match = query_match.unwrap(); // can only fail due to I/O
14906                    let offset_range =
14907                        end_offset - query_match.end()..end_offset - query_match.start();
14908
14909                    if !select_prev_state.wordwise
14910                        || (!buffer.is_inside_word(offset_range.start, None)
14911                            && !buffer.is_inside_word(offset_range.end, None))
14912                    {
14913                        next_selected_range = Some(offset_range);
14914                        break;
14915                    }
14916                }
14917
14918                if let Some(next_selected_range) = next_selected_range {
14919                    self.select_match_ranges(
14920                        next_selected_range,
14921                        last_selection.reversed,
14922                        action.replace_newest,
14923                        Some(Autoscroll::newest()),
14924                        window,
14925                        cx,
14926                    );
14927                } else {
14928                    select_prev_state.done = true;
14929                }
14930            }
14931
14932            self.select_prev_state = Some(select_prev_state);
14933        } else {
14934            let mut only_carets = true;
14935            let mut same_text_selected = true;
14936            let mut selected_text = None;
14937
14938            let mut selections_iter = selections.iter().peekable();
14939            while let Some(selection) = selections_iter.next() {
14940                if selection.start != selection.end {
14941                    only_carets = false;
14942                }
14943
14944                if same_text_selected {
14945                    if selected_text.is_none() {
14946                        selected_text =
14947                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14948                    }
14949
14950                    if let Some(next_selection) = selections_iter.peek() {
14951                        if next_selection.len() == selection.len() {
14952                            let next_selected_text = buffer
14953                                .text_for_range(next_selection.range())
14954                                .collect::<String>();
14955                            if Some(next_selected_text) != selected_text {
14956                                same_text_selected = false;
14957                                selected_text = None;
14958                            }
14959                        } else {
14960                            same_text_selected = false;
14961                            selected_text = None;
14962                        }
14963                    }
14964                }
14965            }
14966
14967            if only_carets {
14968                for selection in &mut selections {
14969                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
14970                    selection.start = word_range.start;
14971                    selection.end = word_range.end;
14972                    selection.goal = SelectionGoal::None;
14973                    selection.reversed = false;
14974                    self.select_match_ranges(
14975                        selection.start..selection.end,
14976                        selection.reversed,
14977                        action.replace_newest,
14978                        Some(Autoscroll::newest()),
14979                        window,
14980                        cx,
14981                    );
14982                }
14983                if selections.len() == 1 {
14984                    let selection = selections
14985                        .last()
14986                        .expect("ensured that there's only one selection");
14987                    let query = buffer
14988                        .text_for_range(selection.start..selection.end)
14989                        .collect::<String>();
14990                    let is_empty = query.is_empty();
14991                    let select_state = SelectNextState {
14992                        query: self.build_query(&[query.chars().rev().collect::<String>()], cx)?,
14993                        wordwise: true,
14994                        done: is_empty,
14995                    };
14996                    self.select_prev_state = Some(select_state);
14997                } else {
14998                    self.select_prev_state = None;
14999                }
15000            } else if let Some(selected_text) = selected_text {
15001                self.select_prev_state = Some(SelectNextState {
15002                    query: self
15003                        .build_query(&[selected_text.chars().rev().collect::<String>()], cx)?,
15004                    wordwise: false,
15005                    done: false,
15006                });
15007                self.select_previous(action, window, cx)?;
15008            }
15009        }
15010        Ok(())
15011    }
15012
15013    /// Builds an `AhoCorasick` automaton from the provided patterns, while
15014    /// setting the case sensitivity based on the global
15015    /// `SelectNextCaseSensitive` setting, if set, otherwise based on the
15016    /// editor's settings.
15017    fn build_query<I, P>(&self, patterns: I, cx: &Context<Self>) -> Result<AhoCorasick, BuildError>
15018    where
15019        I: IntoIterator<Item = P>,
15020        P: AsRef<[u8]>,
15021    {
15022        let case_sensitive = self.select_next_is_case_sensitive.map_or_else(
15023            || EditorSettings::get_global(cx).search.case_sensitive,
15024            |value| value,
15025        );
15026
15027        let mut builder = AhoCorasickBuilder::new();
15028        builder.ascii_case_insensitive(!case_sensitive);
15029        builder.build(patterns)
15030    }
15031
15032    pub fn find_next_match(
15033        &mut self,
15034        _: &FindNextMatch,
15035        window: &mut Window,
15036        cx: &mut Context<Self>,
15037    ) -> Result<()> {
15038        let selections = self.selections.disjoint_anchors_arc();
15039        match selections.first() {
15040            Some(first) if selections.len() >= 2 => {
15041                self.change_selections(Default::default(), window, cx, |s| {
15042                    s.select_ranges([first.range()]);
15043                });
15044            }
15045            _ => self.select_next(
15046                &SelectNext {
15047                    replace_newest: true,
15048                },
15049                window,
15050                cx,
15051            )?,
15052        }
15053        Ok(())
15054    }
15055
15056    pub fn find_previous_match(
15057        &mut self,
15058        _: &FindPreviousMatch,
15059        window: &mut Window,
15060        cx: &mut Context<Self>,
15061    ) -> Result<()> {
15062        let selections = self.selections.disjoint_anchors_arc();
15063        match selections.last() {
15064            Some(last) if selections.len() >= 2 => {
15065                self.change_selections(Default::default(), window, cx, |s| {
15066                    s.select_ranges([last.range()]);
15067                });
15068            }
15069            _ => self.select_previous(
15070                &SelectPrevious {
15071                    replace_newest: true,
15072                },
15073                window,
15074                cx,
15075            )?,
15076        }
15077        Ok(())
15078    }
15079
15080    pub fn toggle_comments(
15081        &mut self,
15082        action: &ToggleComments,
15083        window: &mut Window,
15084        cx: &mut Context<Self>,
15085    ) {
15086        if self.read_only(cx) {
15087            return;
15088        }
15089        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
15090        let text_layout_details = &self.text_layout_details(window);
15091        self.transact(window, cx, |this, window, cx| {
15092            let mut selections = this
15093                .selections
15094                .all::<MultiBufferPoint>(&this.display_snapshot(cx));
15095            let mut edits = Vec::new();
15096            let mut selection_edit_ranges = Vec::new();
15097            let mut last_toggled_row = None;
15098            let snapshot = this.buffer.read(cx).read(cx);
15099            let empty_str: Arc<str> = Arc::default();
15100            let mut suffixes_inserted = Vec::new();
15101            let ignore_indent = action.ignore_indent;
15102
15103            fn comment_prefix_range(
15104                snapshot: &MultiBufferSnapshot,
15105                row: MultiBufferRow,
15106                comment_prefix: &str,
15107                comment_prefix_whitespace: &str,
15108                ignore_indent: bool,
15109            ) -> Range<Point> {
15110                let indent_size = if ignore_indent {
15111                    0
15112                } else {
15113                    snapshot.indent_size_for_line(row).len
15114                };
15115
15116                let start = Point::new(row.0, indent_size);
15117
15118                let mut line_bytes = snapshot
15119                    .bytes_in_range(start..snapshot.max_point())
15120                    .flatten()
15121                    .copied();
15122
15123                // If this line currently begins with the line comment prefix, then record
15124                // the range containing the prefix.
15125                if line_bytes
15126                    .by_ref()
15127                    .take(comment_prefix.len())
15128                    .eq(comment_prefix.bytes())
15129                {
15130                    // Include any whitespace that matches the comment prefix.
15131                    let matching_whitespace_len = line_bytes
15132                        .zip(comment_prefix_whitespace.bytes())
15133                        .take_while(|(a, b)| a == b)
15134                        .count() as u32;
15135                    let end = Point::new(
15136                        start.row,
15137                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
15138                    );
15139                    start..end
15140                } else {
15141                    start..start
15142                }
15143            }
15144
15145            fn comment_suffix_range(
15146                snapshot: &MultiBufferSnapshot,
15147                row: MultiBufferRow,
15148                comment_suffix: &str,
15149                comment_suffix_has_leading_space: bool,
15150            ) -> Range<Point> {
15151                let end = Point::new(row.0, snapshot.line_len(row));
15152                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
15153
15154                let mut line_end_bytes = snapshot
15155                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
15156                    .flatten()
15157                    .copied();
15158
15159                let leading_space_len = if suffix_start_column > 0
15160                    && line_end_bytes.next() == Some(b' ')
15161                    && comment_suffix_has_leading_space
15162                {
15163                    1
15164                } else {
15165                    0
15166                };
15167
15168                // If this line currently begins with the line comment prefix, then record
15169                // the range containing the prefix.
15170                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
15171                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
15172                    start..end
15173                } else {
15174                    end..end
15175                }
15176            }
15177
15178            // TODO: Handle selections that cross excerpts
15179            for selection in &mut selections {
15180                let start_column = snapshot
15181                    .indent_size_for_line(MultiBufferRow(selection.start.row))
15182                    .len;
15183                let language = if let Some(language) =
15184                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
15185                {
15186                    language
15187                } else {
15188                    continue;
15189                };
15190
15191                selection_edit_ranges.clear();
15192
15193                // If multiple selections contain a given row, avoid processing that
15194                // row more than once.
15195                let mut start_row = MultiBufferRow(selection.start.row);
15196                if last_toggled_row == Some(start_row) {
15197                    start_row = start_row.next_row();
15198                }
15199                let end_row =
15200                    if selection.end.row > selection.start.row && selection.end.column == 0 {
15201                        MultiBufferRow(selection.end.row - 1)
15202                    } else {
15203                        MultiBufferRow(selection.end.row)
15204                    };
15205                last_toggled_row = Some(end_row);
15206
15207                if start_row > end_row {
15208                    continue;
15209                }
15210
15211                // If the language has line comments, toggle those.
15212                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
15213
15214                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
15215                if ignore_indent {
15216                    full_comment_prefixes = full_comment_prefixes
15217                        .into_iter()
15218                        .map(|s| Arc::from(s.trim_end()))
15219                        .collect();
15220                }
15221
15222                if !full_comment_prefixes.is_empty() {
15223                    let first_prefix = full_comment_prefixes
15224                        .first()
15225                        .expect("prefixes is non-empty");
15226                    let prefix_trimmed_lengths = full_comment_prefixes
15227                        .iter()
15228                        .map(|p| p.trim_end_matches(' ').len())
15229                        .collect::<SmallVec<[usize; 4]>>();
15230
15231                    let mut all_selection_lines_are_comments = true;
15232
15233                    for row in start_row.0..=end_row.0 {
15234                        let row = MultiBufferRow(row);
15235                        if start_row < end_row && snapshot.is_line_blank(row) {
15236                            continue;
15237                        }
15238
15239                        let prefix_range = full_comment_prefixes
15240                            .iter()
15241                            .zip(prefix_trimmed_lengths.iter().copied())
15242                            .map(|(prefix, trimmed_prefix_len)| {
15243                                comment_prefix_range(
15244                                    snapshot.deref(),
15245                                    row,
15246                                    &prefix[..trimmed_prefix_len],
15247                                    &prefix[trimmed_prefix_len..],
15248                                    ignore_indent,
15249                                )
15250                            })
15251                            .max_by_key(|range| range.end.column - range.start.column)
15252                            .expect("prefixes is non-empty");
15253
15254                        if prefix_range.is_empty() {
15255                            all_selection_lines_are_comments = false;
15256                        }
15257
15258                        selection_edit_ranges.push(prefix_range);
15259                    }
15260
15261                    if all_selection_lines_are_comments {
15262                        edits.extend(
15263                            selection_edit_ranges
15264                                .iter()
15265                                .cloned()
15266                                .map(|range| (range, empty_str.clone())),
15267                        );
15268                    } else {
15269                        let min_column = selection_edit_ranges
15270                            .iter()
15271                            .map(|range| range.start.column)
15272                            .min()
15273                            .unwrap_or(0);
15274                        edits.extend(selection_edit_ranges.iter().map(|range| {
15275                            let position = Point::new(range.start.row, min_column);
15276                            (position..position, first_prefix.clone())
15277                        }));
15278                    }
15279                } else if let Some(BlockCommentConfig {
15280                    start: full_comment_prefix,
15281                    end: comment_suffix,
15282                    ..
15283                }) = language.block_comment()
15284                {
15285                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
15286                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
15287                    let prefix_range = comment_prefix_range(
15288                        snapshot.deref(),
15289                        start_row,
15290                        comment_prefix,
15291                        comment_prefix_whitespace,
15292                        ignore_indent,
15293                    );
15294                    let suffix_range = comment_suffix_range(
15295                        snapshot.deref(),
15296                        end_row,
15297                        comment_suffix.trim_start_matches(' '),
15298                        comment_suffix.starts_with(' '),
15299                    );
15300
15301                    if prefix_range.is_empty() || suffix_range.is_empty() {
15302                        edits.push((
15303                            prefix_range.start..prefix_range.start,
15304                            full_comment_prefix.clone(),
15305                        ));
15306                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
15307                        suffixes_inserted.push((end_row, comment_suffix.len()));
15308                    } else {
15309                        edits.push((prefix_range, empty_str.clone()));
15310                        edits.push((suffix_range, empty_str.clone()));
15311                    }
15312                } else {
15313                    continue;
15314                }
15315            }
15316
15317            drop(snapshot);
15318            this.buffer.update(cx, |buffer, cx| {
15319                buffer.edit(edits, None, cx);
15320            });
15321
15322            // Adjust selections so that they end before any comment suffixes that
15323            // were inserted.
15324            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
15325            let mut selections = this.selections.all::<Point>(&this.display_snapshot(cx));
15326            let snapshot = this.buffer.read(cx).read(cx);
15327            for selection in &mut selections {
15328                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
15329                    match row.cmp(&MultiBufferRow(selection.end.row)) {
15330                        Ordering::Less => {
15331                            suffixes_inserted.next();
15332                            continue;
15333                        }
15334                        Ordering::Greater => break,
15335                        Ordering::Equal => {
15336                            if selection.end.column == snapshot.line_len(row) {
15337                                if selection.is_empty() {
15338                                    selection.start.column -= suffix_len as u32;
15339                                }
15340                                selection.end.column -= suffix_len as u32;
15341                            }
15342                            break;
15343                        }
15344                    }
15345                }
15346            }
15347
15348            drop(snapshot);
15349            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
15350
15351            let selections = this.selections.all::<Point>(&this.display_snapshot(cx));
15352            let selections_on_single_row = selections.windows(2).all(|selections| {
15353                selections[0].start.row == selections[1].start.row
15354                    && selections[0].end.row == selections[1].end.row
15355                    && selections[0].start.row == selections[0].end.row
15356            });
15357            let selections_selecting = selections
15358                .iter()
15359                .any(|selection| selection.start != selection.end);
15360            let advance_downwards = action.advance_downwards
15361                && selections_on_single_row
15362                && !selections_selecting
15363                && !matches!(this.mode, EditorMode::SingleLine);
15364
15365            if advance_downwards {
15366                let snapshot = this.buffer.read(cx).snapshot(cx);
15367
15368                this.change_selections(Default::default(), window, cx, |s| {
15369                    s.move_cursors_with(|display_snapshot, display_point, _| {
15370                        let mut point = display_point.to_point(display_snapshot);
15371                        point.row += 1;
15372                        point = snapshot.clip_point(point, Bias::Left);
15373                        let display_point = point.to_display_point(display_snapshot);
15374                        let goal = SelectionGoal::HorizontalPosition(
15375                            display_snapshot
15376                                .x_for_display_point(display_point, text_layout_details)
15377                                .into(),
15378                        );
15379                        (display_point, goal)
15380                    })
15381                });
15382            }
15383        });
15384    }
15385
15386    pub fn select_enclosing_symbol(
15387        &mut self,
15388        _: &SelectEnclosingSymbol,
15389        window: &mut Window,
15390        cx: &mut Context<Self>,
15391    ) {
15392        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15393
15394        let buffer = self.buffer.read(cx).snapshot(cx);
15395        let old_selections = self
15396            .selections
15397            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
15398            .into_boxed_slice();
15399
15400        fn update_selection(
15401            selection: &Selection<MultiBufferOffset>,
15402            buffer_snap: &MultiBufferSnapshot,
15403        ) -> Option<Selection<MultiBufferOffset>> {
15404            let cursor = selection.head();
15405            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
15406            for symbol in symbols.iter().rev() {
15407                let start = symbol.range.start.to_offset(buffer_snap);
15408                let end = symbol.range.end.to_offset(buffer_snap);
15409                let new_range = start..end;
15410                if start < selection.start || end > selection.end {
15411                    return Some(Selection {
15412                        id: selection.id,
15413                        start: new_range.start,
15414                        end: new_range.end,
15415                        goal: SelectionGoal::None,
15416                        reversed: selection.reversed,
15417                    });
15418                }
15419            }
15420            None
15421        }
15422
15423        let mut selected_larger_symbol = false;
15424        let new_selections = old_selections
15425            .iter()
15426            .map(|selection| match update_selection(selection, &buffer) {
15427                Some(new_selection) => {
15428                    if new_selection.range() != selection.range() {
15429                        selected_larger_symbol = true;
15430                    }
15431                    new_selection
15432                }
15433                None => selection.clone(),
15434            })
15435            .collect::<Vec<_>>();
15436
15437        if selected_larger_symbol {
15438            self.change_selections(Default::default(), window, cx, |s| {
15439                s.select(new_selections);
15440            });
15441        }
15442    }
15443
15444    pub fn select_larger_syntax_node(
15445        &mut self,
15446        _: &SelectLargerSyntaxNode,
15447        window: &mut Window,
15448        cx: &mut Context<Self>,
15449    ) {
15450        let Some(visible_row_count) = self.visible_row_count() else {
15451            return;
15452        };
15453        let old_selections: Box<[_]> = self
15454            .selections
15455            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
15456            .into();
15457        if old_selections.is_empty() {
15458            return;
15459        }
15460
15461        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15462
15463        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15464        let buffer = self.buffer.read(cx).snapshot(cx);
15465
15466        let mut selected_larger_node = false;
15467        let mut new_selections = old_selections
15468            .iter()
15469            .map(|selection| {
15470                let old_range = selection.start..selection.end;
15471
15472                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
15473                    // manually select word at selection
15474                    if ["string_content", "inline"].contains(&node.kind()) {
15475                        let (word_range, _) = buffer.surrounding_word(old_range.start, None);
15476                        // ignore if word is already selected
15477                        if !word_range.is_empty() && old_range != word_range {
15478                            let (last_word_range, _) = buffer.surrounding_word(old_range.end, None);
15479                            // only select word if start and end point belongs to same word
15480                            if word_range == last_word_range {
15481                                selected_larger_node = true;
15482                                return Selection {
15483                                    id: selection.id,
15484                                    start: word_range.start,
15485                                    end: word_range.end,
15486                                    goal: SelectionGoal::None,
15487                                    reversed: selection.reversed,
15488                                };
15489                            }
15490                        }
15491                    }
15492                }
15493
15494                let mut new_range = old_range.clone();
15495                while let Some((node, range)) = buffer.syntax_ancestor(new_range.clone()) {
15496                    new_range = range;
15497                    if !node.is_named() {
15498                        continue;
15499                    }
15500                    if !display_map.intersects_fold(new_range.start)
15501                        && !display_map.intersects_fold(new_range.end)
15502                    {
15503                        break;
15504                    }
15505                }
15506
15507                selected_larger_node |= new_range != old_range;
15508                Selection {
15509                    id: selection.id,
15510                    start: new_range.start,
15511                    end: new_range.end,
15512                    goal: SelectionGoal::None,
15513                    reversed: selection.reversed,
15514                }
15515            })
15516            .collect::<Vec<_>>();
15517
15518        if !selected_larger_node {
15519            return; // don't put this call in the history
15520        }
15521
15522        // scroll based on transformation done to the last selection created by the user
15523        let (last_old, last_new) = old_selections
15524            .last()
15525            .zip(new_selections.last().cloned())
15526            .expect("old_selections isn't empty");
15527
15528        // revert selection
15529        let is_selection_reversed = {
15530            let should_newest_selection_be_reversed = last_old.start != last_new.start;
15531            new_selections.last_mut().expect("checked above").reversed =
15532                should_newest_selection_be_reversed;
15533            should_newest_selection_be_reversed
15534        };
15535
15536        if selected_larger_node {
15537            self.select_syntax_node_history.disable_clearing = true;
15538            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15539                s.select(new_selections.clone());
15540            });
15541            self.select_syntax_node_history.disable_clearing = false;
15542        }
15543
15544        let start_row = last_new.start.to_display_point(&display_map).row().0;
15545        let end_row = last_new.end.to_display_point(&display_map).row().0;
15546        let selection_height = end_row - start_row + 1;
15547        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
15548
15549        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
15550        let scroll_behavior = if fits_on_the_screen {
15551            self.request_autoscroll(Autoscroll::fit(), cx);
15552            SelectSyntaxNodeScrollBehavior::FitSelection
15553        } else if is_selection_reversed {
15554            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15555            SelectSyntaxNodeScrollBehavior::CursorTop
15556        } else {
15557            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15558            SelectSyntaxNodeScrollBehavior::CursorBottom
15559        };
15560
15561        self.select_syntax_node_history.push((
15562            old_selections,
15563            scroll_behavior,
15564            is_selection_reversed,
15565        ));
15566    }
15567
15568    pub fn select_smaller_syntax_node(
15569        &mut self,
15570        _: &SelectSmallerSyntaxNode,
15571        window: &mut Window,
15572        cx: &mut Context<Self>,
15573    ) {
15574        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15575
15576        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
15577            self.select_syntax_node_history.pop()
15578        {
15579            if let Some(selection) = selections.last_mut() {
15580                selection.reversed = is_selection_reversed;
15581            }
15582
15583            self.select_syntax_node_history.disable_clearing = true;
15584            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15585                s.select(selections.to_vec());
15586            });
15587            self.select_syntax_node_history.disable_clearing = false;
15588
15589            match scroll_behavior {
15590                SelectSyntaxNodeScrollBehavior::CursorTop => {
15591                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15592                }
15593                SelectSyntaxNodeScrollBehavior::FitSelection => {
15594                    self.request_autoscroll(Autoscroll::fit(), cx);
15595                }
15596                SelectSyntaxNodeScrollBehavior::CursorBottom => {
15597                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15598                }
15599            }
15600        }
15601    }
15602
15603    pub fn unwrap_syntax_node(
15604        &mut self,
15605        _: &UnwrapSyntaxNode,
15606        window: &mut Window,
15607        cx: &mut Context<Self>,
15608    ) {
15609        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15610
15611        let buffer = self.buffer.read(cx).snapshot(cx);
15612        let selections = self
15613            .selections
15614            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
15615            .into_iter()
15616            // subtracting the offset requires sorting
15617            .sorted_by_key(|i| i.start);
15618
15619        let full_edits = selections
15620            .into_iter()
15621            .filter_map(|selection| {
15622                let child = if selection.is_empty()
15623                    && let Some((_, ancestor_range)) =
15624                        buffer.syntax_ancestor(selection.start..selection.end)
15625                {
15626                    ancestor_range
15627                } else {
15628                    selection.range()
15629                };
15630
15631                let mut parent = child.clone();
15632                while let Some((_, ancestor_range)) = buffer.syntax_ancestor(parent.clone()) {
15633                    parent = ancestor_range;
15634                    if parent.start < child.start || parent.end > child.end {
15635                        break;
15636                    }
15637                }
15638
15639                if parent == child {
15640                    return None;
15641                }
15642                let text = buffer.text_for_range(child).collect::<String>();
15643                Some((selection.id, parent, text))
15644            })
15645            .collect::<Vec<_>>();
15646        if full_edits.is_empty() {
15647            return;
15648        }
15649
15650        self.transact(window, cx, |this, window, cx| {
15651            this.buffer.update(cx, |buffer, cx| {
15652                buffer.edit(
15653                    full_edits
15654                        .iter()
15655                        .map(|(_, p, t)| (p.clone(), t.clone()))
15656                        .collect::<Vec<_>>(),
15657                    None,
15658                    cx,
15659                );
15660            });
15661            this.change_selections(Default::default(), window, cx, |s| {
15662                let mut offset = 0;
15663                let mut selections = vec![];
15664                for (id, parent, text) in full_edits {
15665                    let start = parent.start - offset;
15666                    offset += (parent.end - parent.start) - text.len();
15667                    selections.push(Selection {
15668                        id,
15669                        start,
15670                        end: start + text.len(),
15671                        reversed: false,
15672                        goal: Default::default(),
15673                    });
15674                }
15675                s.select(selections);
15676            });
15677        });
15678    }
15679
15680    pub fn select_next_syntax_node(
15681        &mut self,
15682        _: &SelectNextSyntaxNode,
15683        window: &mut Window,
15684        cx: &mut Context<Self>,
15685    ) {
15686        let old_selections: Box<[_]> = self
15687            .selections
15688            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
15689            .into();
15690        if old_selections.is_empty() {
15691            return;
15692        }
15693
15694        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15695
15696        let buffer = self.buffer.read(cx).snapshot(cx);
15697        let mut selected_sibling = false;
15698
15699        let new_selections = old_selections
15700            .iter()
15701            .map(|selection| {
15702                let old_range = selection.start..selection.end;
15703
15704                let old_range =
15705                    old_range.start.to_offset(&buffer)..old_range.end.to_offset(&buffer);
15706                let excerpt = buffer.excerpt_containing(old_range.clone());
15707
15708                if let Some(mut excerpt) = excerpt
15709                    && let Some(node) = excerpt
15710                        .buffer()
15711                        .syntax_next_sibling(excerpt.map_range_to_buffer(old_range))
15712                {
15713                    let new_range = excerpt.map_range_from_buffer(
15714                        BufferOffset(node.byte_range().start)..BufferOffset(node.byte_range().end),
15715                    );
15716                    selected_sibling = true;
15717                    Selection {
15718                        id: selection.id,
15719                        start: new_range.start,
15720                        end: new_range.end,
15721                        goal: SelectionGoal::None,
15722                        reversed: selection.reversed,
15723                    }
15724                } else {
15725                    selection.clone()
15726                }
15727            })
15728            .collect::<Vec<_>>();
15729
15730        if selected_sibling {
15731            self.change_selections(
15732                SelectionEffects::scroll(Autoscroll::fit()),
15733                window,
15734                cx,
15735                |s| {
15736                    s.select(new_selections);
15737                },
15738            );
15739        }
15740    }
15741
15742    pub fn select_prev_syntax_node(
15743        &mut self,
15744        _: &SelectPreviousSyntaxNode,
15745        window: &mut Window,
15746        cx: &mut Context<Self>,
15747    ) {
15748        let old_selections: Box<[_]> = self
15749            .selections
15750            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
15751            .into();
15752        if old_selections.is_empty() {
15753            return;
15754        }
15755
15756        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15757
15758        let buffer = self.buffer.read(cx).snapshot(cx);
15759        let mut selected_sibling = false;
15760
15761        let new_selections = old_selections
15762            .iter()
15763            .map(|selection| {
15764                let old_range = selection.start..selection.end;
15765                let old_range =
15766                    old_range.start.to_offset(&buffer)..old_range.end.to_offset(&buffer);
15767                let excerpt = buffer.excerpt_containing(old_range.clone());
15768
15769                if let Some(mut excerpt) = excerpt
15770                    && let Some(node) = excerpt
15771                        .buffer()
15772                        .syntax_prev_sibling(excerpt.map_range_to_buffer(old_range))
15773                {
15774                    let new_range = excerpt.map_range_from_buffer(
15775                        BufferOffset(node.byte_range().start)..BufferOffset(node.byte_range().end),
15776                    );
15777                    selected_sibling = true;
15778                    Selection {
15779                        id: selection.id,
15780                        start: new_range.start,
15781                        end: new_range.end,
15782                        goal: SelectionGoal::None,
15783                        reversed: selection.reversed,
15784                    }
15785                } else {
15786                    selection.clone()
15787                }
15788            })
15789            .collect::<Vec<_>>();
15790
15791        if selected_sibling {
15792            self.change_selections(
15793                SelectionEffects::scroll(Autoscroll::fit()),
15794                window,
15795                cx,
15796                |s| {
15797                    s.select(new_selections);
15798                },
15799            );
15800        }
15801    }
15802
15803    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
15804        if !EditorSettings::get_global(cx).gutter.runnables {
15805            self.clear_tasks();
15806            return Task::ready(());
15807        }
15808        let project = self.project().map(Entity::downgrade);
15809        let task_sources = self.lsp_task_sources(cx);
15810        let multi_buffer = self.buffer.downgrade();
15811        cx.spawn_in(window, async move |editor, cx| {
15812            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
15813            let Some(project) = project.and_then(|p| p.upgrade()) else {
15814                return;
15815            };
15816            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
15817                this.display_map.update(cx, |map, cx| map.snapshot(cx))
15818            }) else {
15819                return;
15820            };
15821
15822            let hide_runnables = project
15823                .update(cx, |project, _| project.is_via_collab())
15824                .unwrap_or(true);
15825            if hide_runnables {
15826                return;
15827            }
15828            let new_rows =
15829                cx.background_spawn({
15830                    let snapshot = display_snapshot.clone();
15831                    async move {
15832                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
15833                    }
15834                })
15835                    .await;
15836            let Ok(lsp_tasks) =
15837                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
15838            else {
15839                return;
15840            };
15841            let lsp_tasks = lsp_tasks.await;
15842
15843            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
15844                lsp_tasks
15845                    .into_iter()
15846                    .flat_map(|(kind, tasks)| {
15847                        tasks.into_iter().filter_map(move |(location, task)| {
15848                            Some((kind.clone(), location?, task))
15849                        })
15850                    })
15851                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
15852                        let buffer = location.target.buffer;
15853                        let buffer_snapshot = buffer.read(cx).snapshot();
15854                        let offset = display_snapshot.buffer_snapshot().excerpts().find_map(
15855                            |(excerpt_id, snapshot, _)| {
15856                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
15857                                    display_snapshot
15858                                        .buffer_snapshot()
15859                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
15860                                } else {
15861                                    None
15862                                }
15863                            },
15864                        );
15865                        if let Some(offset) = offset {
15866                            let task_buffer_range =
15867                                location.target.range.to_point(&buffer_snapshot);
15868                            let context_buffer_range =
15869                                task_buffer_range.to_offset(&buffer_snapshot);
15870                            let context_range = BufferOffset(context_buffer_range.start)
15871                                ..BufferOffset(context_buffer_range.end);
15872
15873                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
15874                                .or_insert_with(|| RunnableTasks {
15875                                    templates: Vec::new(),
15876                                    offset,
15877                                    column: task_buffer_range.start.column,
15878                                    extra_variables: HashMap::default(),
15879                                    context_range,
15880                                })
15881                                .templates
15882                                .push((kind, task.original_task().clone()));
15883                        }
15884
15885                        acc
15886                    })
15887            }) else {
15888                return;
15889            };
15890
15891            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
15892                buffer.language_settings(cx).tasks.prefer_lsp
15893            }) else {
15894                return;
15895            };
15896
15897            let rows = Self::runnable_rows(
15898                project,
15899                display_snapshot,
15900                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
15901                new_rows,
15902                cx.clone(),
15903            )
15904            .await;
15905            editor
15906                .update(cx, |editor, _| {
15907                    editor.clear_tasks();
15908                    for (key, mut value) in rows {
15909                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
15910                            value.templates.extend(lsp_tasks.templates);
15911                        }
15912
15913                        editor.insert_tasks(key, value);
15914                    }
15915                    for (key, value) in lsp_tasks_by_rows {
15916                        editor.insert_tasks(key, value);
15917                    }
15918                })
15919                .ok();
15920        })
15921    }
15922    fn fetch_runnable_ranges(
15923        snapshot: &DisplaySnapshot,
15924        range: Range<Anchor>,
15925    ) -> Vec<(Range<MultiBufferOffset>, language::RunnableRange)> {
15926        snapshot.buffer_snapshot().runnable_ranges(range).collect()
15927    }
15928
15929    fn runnable_rows(
15930        project: Entity<Project>,
15931        snapshot: DisplaySnapshot,
15932        prefer_lsp: bool,
15933        runnable_ranges: Vec<(Range<MultiBufferOffset>, language::RunnableRange)>,
15934        cx: AsyncWindowContext,
15935    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
15936        cx.spawn(async move |cx| {
15937            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
15938            for (run_range, mut runnable) in runnable_ranges {
15939                let Some(tasks) = cx
15940                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
15941                    .ok()
15942                else {
15943                    continue;
15944                };
15945                let mut tasks = tasks.await;
15946
15947                if prefer_lsp {
15948                    tasks.retain(|(task_kind, _)| {
15949                        !matches!(task_kind, TaskSourceKind::Language { .. })
15950                    });
15951                }
15952                if tasks.is_empty() {
15953                    continue;
15954                }
15955
15956                let point = run_range.start.to_point(&snapshot.buffer_snapshot());
15957                let Some(row) = snapshot
15958                    .buffer_snapshot()
15959                    .buffer_line_for_row(MultiBufferRow(point.row))
15960                    .map(|(_, range)| range.start.row)
15961                else {
15962                    continue;
15963                };
15964
15965                let context_range =
15966                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
15967                runnable_rows.push((
15968                    (runnable.buffer_id, row),
15969                    RunnableTasks {
15970                        templates: tasks,
15971                        offset: snapshot.buffer_snapshot().anchor_before(run_range.start),
15972                        context_range,
15973                        column: point.column,
15974                        extra_variables: runnable.extra_captures,
15975                    },
15976                ));
15977            }
15978            runnable_rows
15979        })
15980    }
15981
15982    fn templates_with_tags(
15983        project: &Entity<Project>,
15984        runnable: &mut Runnable,
15985        cx: &mut App,
15986    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
15987        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
15988            let (worktree_id, file) = project
15989                .buffer_for_id(runnable.buffer, cx)
15990                .and_then(|buffer| buffer.read(cx).file())
15991                .map(|file| (file.worktree_id(cx), file.clone()))
15992                .unzip();
15993
15994            (
15995                project.task_store().read(cx).task_inventory().cloned(),
15996                worktree_id,
15997                file,
15998            )
15999        });
16000
16001        let tags = mem::take(&mut runnable.tags);
16002        let language = runnable.language.clone();
16003        cx.spawn(async move |cx| {
16004            let mut templates_with_tags = Vec::new();
16005            if let Some(inventory) = inventory {
16006                for RunnableTag(tag) in tags {
16007                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
16008                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
16009                    }) else {
16010                        return templates_with_tags;
16011                    };
16012                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
16013                        move |(_, template)| {
16014                            template.tags.iter().any(|source_tag| source_tag == &tag)
16015                        },
16016                    ));
16017                }
16018            }
16019            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
16020
16021            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
16022                // Strongest source wins; if we have worktree tag binding, prefer that to
16023                // global and language bindings;
16024                // if we have a global binding, prefer that to language binding.
16025                let first_mismatch = templates_with_tags
16026                    .iter()
16027                    .position(|(tag_source, _)| tag_source != leading_tag_source);
16028                if let Some(index) = first_mismatch {
16029                    templates_with_tags.truncate(index);
16030                }
16031            }
16032
16033            templates_with_tags
16034        })
16035    }
16036
16037    pub fn move_to_enclosing_bracket(
16038        &mut self,
16039        _: &MoveToEnclosingBracket,
16040        window: &mut Window,
16041        cx: &mut Context<Self>,
16042    ) {
16043        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16044        self.change_selections(Default::default(), window, cx, |s| {
16045            s.move_offsets_with(|snapshot, selection| {
16046                let Some(enclosing_bracket_ranges) =
16047                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
16048                else {
16049                    return;
16050                };
16051
16052                let mut best_length = usize::MAX;
16053                let mut best_inside = false;
16054                let mut best_in_bracket_range = false;
16055                let mut best_destination = None;
16056                for (open, close) in enclosing_bracket_ranges {
16057                    let close = close.to_inclusive();
16058                    let length = *close.end() - open.start;
16059                    let inside = selection.start >= open.end && selection.end <= *close.start();
16060                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
16061                        || close.contains(&selection.head());
16062
16063                    // If best is next to a bracket and current isn't, skip
16064                    if !in_bracket_range && best_in_bracket_range {
16065                        continue;
16066                    }
16067
16068                    // Prefer smaller lengths unless best is inside and current isn't
16069                    if length > best_length && (best_inside || !inside) {
16070                        continue;
16071                    }
16072
16073                    best_length = length;
16074                    best_inside = inside;
16075                    best_in_bracket_range = in_bracket_range;
16076                    best_destination = Some(
16077                        if close.contains(&selection.start) && close.contains(&selection.end) {
16078                            if inside { open.end } else { open.start }
16079                        } else if inside {
16080                            *close.start()
16081                        } else {
16082                            *close.end()
16083                        },
16084                    );
16085                }
16086
16087                if let Some(destination) = best_destination {
16088                    selection.collapse_to(destination, SelectionGoal::None);
16089                }
16090            })
16091        });
16092    }
16093
16094    pub fn undo_selection(
16095        &mut self,
16096        _: &UndoSelection,
16097        window: &mut Window,
16098        cx: &mut Context<Self>,
16099    ) {
16100        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16101        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
16102            self.selection_history.mode = SelectionHistoryMode::Undoing;
16103            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
16104                this.end_selection(window, cx);
16105                this.change_selections(
16106                    SelectionEffects::scroll(Autoscroll::newest()),
16107                    window,
16108                    cx,
16109                    |s| s.select_anchors(entry.selections.to_vec()),
16110                );
16111            });
16112            self.selection_history.mode = SelectionHistoryMode::Normal;
16113
16114            self.select_next_state = entry.select_next_state;
16115            self.select_prev_state = entry.select_prev_state;
16116            self.add_selections_state = entry.add_selections_state;
16117        }
16118    }
16119
16120    pub fn redo_selection(
16121        &mut self,
16122        _: &RedoSelection,
16123        window: &mut Window,
16124        cx: &mut Context<Self>,
16125    ) {
16126        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16127        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
16128            self.selection_history.mode = SelectionHistoryMode::Redoing;
16129            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
16130                this.end_selection(window, cx);
16131                this.change_selections(
16132                    SelectionEffects::scroll(Autoscroll::newest()),
16133                    window,
16134                    cx,
16135                    |s| s.select_anchors(entry.selections.to_vec()),
16136                );
16137            });
16138            self.selection_history.mode = SelectionHistoryMode::Normal;
16139
16140            self.select_next_state = entry.select_next_state;
16141            self.select_prev_state = entry.select_prev_state;
16142            self.add_selections_state = entry.add_selections_state;
16143        }
16144    }
16145
16146    pub fn expand_excerpts(
16147        &mut self,
16148        action: &ExpandExcerpts,
16149        _: &mut Window,
16150        cx: &mut Context<Self>,
16151    ) {
16152        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
16153    }
16154
16155    pub fn expand_excerpts_down(
16156        &mut self,
16157        action: &ExpandExcerptsDown,
16158        _: &mut Window,
16159        cx: &mut Context<Self>,
16160    ) {
16161        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
16162    }
16163
16164    pub fn expand_excerpts_up(
16165        &mut self,
16166        action: &ExpandExcerptsUp,
16167        _: &mut Window,
16168        cx: &mut Context<Self>,
16169    ) {
16170        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
16171    }
16172
16173    pub fn expand_excerpts_for_direction(
16174        &mut self,
16175        lines: u32,
16176        direction: ExpandExcerptDirection,
16177
16178        cx: &mut Context<Self>,
16179    ) {
16180        let selections = self.selections.disjoint_anchors_arc();
16181
16182        let lines = if lines == 0 {
16183            EditorSettings::get_global(cx).expand_excerpt_lines
16184        } else {
16185            lines
16186        };
16187
16188        self.buffer.update(cx, |buffer, cx| {
16189            let snapshot = buffer.snapshot(cx);
16190            let mut excerpt_ids = selections
16191                .iter()
16192                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
16193                .collect::<Vec<_>>();
16194            excerpt_ids.sort();
16195            excerpt_ids.dedup();
16196            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
16197        })
16198    }
16199
16200    pub fn expand_excerpt(
16201        &mut self,
16202        excerpt: ExcerptId,
16203        direction: ExpandExcerptDirection,
16204        window: &mut Window,
16205        cx: &mut Context<Self>,
16206    ) {
16207        let current_scroll_position = self.scroll_position(cx);
16208        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
16209        let mut scroll = None;
16210
16211        if direction == ExpandExcerptDirection::Down {
16212            let multi_buffer = self.buffer.read(cx);
16213            let snapshot = multi_buffer.snapshot(cx);
16214            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt)
16215                && let Some(buffer) = multi_buffer.buffer(buffer_id)
16216                && let Some(excerpt_range) = snapshot.context_range_for_excerpt(excerpt)
16217            {
16218                let buffer_snapshot = buffer.read(cx).snapshot();
16219                let excerpt_end_row = Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
16220                let last_row = buffer_snapshot.max_point().row;
16221                let lines_below = last_row.saturating_sub(excerpt_end_row);
16222                if lines_below >= lines_to_expand {
16223                    scroll = Some(
16224                        current_scroll_position
16225                            + gpui::Point::new(0.0, lines_to_expand as ScrollOffset),
16226                    );
16227                }
16228            }
16229        }
16230        if direction == ExpandExcerptDirection::Up
16231            && self
16232                .buffer
16233                .read(cx)
16234                .snapshot(cx)
16235                .excerpt_before(excerpt)
16236                .is_none()
16237        {
16238            scroll = Some(current_scroll_position);
16239        }
16240
16241        self.buffer.update(cx, |buffer, cx| {
16242            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
16243        });
16244
16245        if let Some(new_scroll_position) = scroll {
16246            self.set_scroll_position(new_scroll_position, window, cx);
16247        }
16248    }
16249
16250    pub fn go_to_singleton_buffer_point(
16251        &mut self,
16252        point: Point,
16253        window: &mut Window,
16254        cx: &mut Context<Self>,
16255    ) {
16256        self.go_to_singleton_buffer_range(point..point, window, cx);
16257    }
16258
16259    pub fn go_to_singleton_buffer_range(
16260        &mut self,
16261        range: Range<Point>,
16262        window: &mut Window,
16263        cx: &mut Context<Self>,
16264    ) {
16265        let multibuffer = self.buffer().read(cx);
16266        let Some(buffer) = multibuffer.as_singleton() else {
16267            return;
16268        };
16269        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
16270            return;
16271        };
16272        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
16273            return;
16274        };
16275        self.change_selections(
16276            SelectionEffects::default().nav_history(true),
16277            window,
16278            cx,
16279            |s| s.select_anchor_ranges([start..end]),
16280        );
16281    }
16282
16283    pub fn go_to_diagnostic(
16284        &mut self,
16285        action: &GoToDiagnostic,
16286        window: &mut Window,
16287        cx: &mut Context<Self>,
16288    ) {
16289        if !self.diagnostics_enabled() {
16290            return;
16291        }
16292        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16293        self.go_to_diagnostic_impl(Direction::Next, action.severity, window, cx)
16294    }
16295
16296    pub fn go_to_prev_diagnostic(
16297        &mut self,
16298        action: &GoToPreviousDiagnostic,
16299        window: &mut Window,
16300        cx: &mut Context<Self>,
16301    ) {
16302        if !self.diagnostics_enabled() {
16303            return;
16304        }
16305        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16306        self.go_to_diagnostic_impl(Direction::Prev, action.severity, window, cx)
16307    }
16308
16309    pub fn go_to_diagnostic_impl(
16310        &mut self,
16311        direction: Direction,
16312        severity: GoToDiagnosticSeverityFilter,
16313        window: &mut Window,
16314        cx: &mut Context<Self>,
16315    ) {
16316        let buffer = self.buffer.read(cx).snapshot(cx);
16317        let selection = self
16318            .selections
16319            .newest::<MultiBufferOffset>(&self.display_snapshot(cx));
16320
16321        let mut active_group_id = None;
16322        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics
16323            && active_group.active_range.start.to_offset(&buffer) == selection.start
16324        {
16325            active_group_id = Some(active_group.group_id);
16326        }
16327
16328        fn filtered<'a>(
16329            severity: GoToDiagnosticSeverityFilter,
16330            diagnostics: impl Iterator<Item = DiagnosticEntryRef<'a, MultiBufferOffset>>,
16331        ) -> impl Iterator<Item = DiagnosticEntryRef<'a, MultiBufferOffset>> {
16332            diagnostics
16333                .filter(move |entry| severity.matches(entry.diagnostic.severity))
16334                .filter(|entry| entry.range.start != entry.range.end)
16335                .filter(|entry| !entry.diagnostic.is_unnecessary)
16336        }
16337
16338        let before = filtered(
16339            severity,
16340            buffer
16341                .diagnostics_in_range(MultiBufferOffset(0)..selection.start)
16342                .filter(|entry| entry.range.start <= selection.start),
16343        );
16344        let after = filtered(
16345            severity,
16346            buffer
16347                .diagnostics_in_range(selection.start..buffer.len())
16348                .filter(|entry| entry.range.start >= selection.start),
16349        );
16350
16351        let mut found: Option<DiagnosticEntryRef<MultiBufferOffset>> = None;
16352        if direction == Direction::Prev {
16353            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
16354            {
16355                for diagnostic in prev_diagnostics.into_iter().rev() {
16356                    if diagnostic.range.start != selection.start
16357                        || active_group_id
16358                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
16359                    {
16360                        found = Some(diagnostic);
16361                        break 'outer;
16362                    }
16363                }
16364            }
16365        } else {
16366            for diagnostic in after.chain(before) {
16367                if diagnostic.range.start != selection.start
16368                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
16369                {
16370                    found = Some(diagnostic);
16371                    break;
16372                }
16373            }
16374        }
16375        let Some(next_diagnostic) = found else {
16376            return;
16377        };
16378
16379        let next_diagnostic_start = buffer.anchor_after(next_diagnostic.range.start);
16380        let Some(buffer_id) = buffer.buffer_id_for_anchor(next_diagnostic_start) else {
16381            return;
16382        };
16383        let snapshot = self.snapshot(window, cx);
16384        if snapshot.intersects_fold(next_diagnostic.range.start) {
16385            self.unfold_ranges(
16386                std::slice::from_ref(&next_diagnostic.range),
16387                true,
16388                false,
16389                cx,
16390            );
16391        }
16392        self.change_selections(Default::default(), window, cx, |s| {
16393            s.select_ranges(vec![
16394                next_diagnostic.range.start..next_diagnostic.range.start,
16395            ])
16396        });
16397        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
16398        self.refresh_edit_prediction(false, true, window, cx);
16399    }
16400
16401    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
16402        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16403        let snapshot = self.snapshot(window, cx);
16404        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
16405        self.go_to_hunk_before_or_after_position(
16406            &snapshot,
16407            selection.head(),
16408            Direction::Next,
16409            window,
16410            cx,
16411        );
16412    }
16413
16414    pub fn go_to_hunk_before_or_after_position(
16415        &mut self,
16416        snapshot: &EditorSnapshot,
16417        position: Point,
16418        direction: Direction,
16419        window: &mut Window,
16420        cx: &mut Context<Editor>,
16421    ) {
16422        let row = if direction == Direction::Next {
16423            self.hunk_after_position(snapshot, position)
16424                .map(|hunk| hunk.row_range.start)
16425        } else {
16426            self.hunk_before_position(snapshot, position)
16427        };
16428
16429        if let Some(row) = row {
16430            let destination = Point::new(row.0, 0);
16431            let autoscroll = Autoscroll::center();
16432
16433            self.unfold_ranges(&[destination..destination], false, false, cx);
16434            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16435                s.select_ranges([destination..destination]);
16436            });
16437        }
16438    }
16439
16440    fn hunk_after_position(
16441        &mut self,
16442        snapshot: &EditorSnapshot,
16443        position: Point,
16444    ) -> Option<MultiBufferDiffHunk> {
16445        snapshot
16446            .buffer_snapshot()
16447            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
16448            .find(|hunk| hunk.row_range.start.0 > position.row)
16449            .or_else(|| {
16450                snapshot
16451                    .buffer_snapshot()
16452                    .diff_hunks_in_range(Point::zero()..position)
16453                    .find(|hunk| hunk.row_range.end.0 < position.row)
16454            })
16455    }
16456
16457    fn go_to_prev_hunk(
16458        &mut self,
16459        _: &GoToPreviousHunk,
16460        window: &mut Window,
16461        cx: &mut Context<Self>,
16462    ) {
16463        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16464        let snapshot = self.snapshot(window, cx);
16465        let selection = self.selections.newest::<Point>(&snapshot.display_snapshot);
16466        self.go_to_hunk_before_or_after_position(
16467            &snapshot,
16468            selection.head(),
16469            Direction::Prev,
16470            window,
16471            cx,
16472        );
16473    }
16474
16475    fn hunk_before_position(
16476        &mut self,
16477        snapshot: &EditorSnapshot,
16478        position: Point,
16479    ) -> Option<MultiBufferRow> {
16480        snapshot
16481            .buffer_snapshot()
16482            .diff_hunk_before(position)
16483            .or_else(|| snapshot.buffer_snapshot().diff_hunk_before(Point::MAX))
16484    }
16485
16486    fn go_to_next_change(
16487        &mut self,
16488        _: &GoToNextChange,
16489        window: &mut Window,
16490        cx: &mut Context<Self>,
16491    ) {
16492        if let Some(selections) = self
16493            .change_list
16494            .next_change(1, Direction::Next)
16495            .map(|s| s.to_vec())
16496        {
16497            self.change_selections(Default::default(), window, cx, |s| {
16498                let map = s.display_snapshot();
16499                s.select_display_ranges(selections.iter().map(|a| {
16500                    let point = a.to_display_point(&map);
16501                    point..point
16502                }))
16503            })
16504        }
16505    }
16506
16507    fn go_to_previous_change(
16508        &mut self,
16509        _: &GoToPreviousChange,
16510        window: &mut Window,
16511        cx: &mut Context<Self>,
16512    ) {
16513        if let Some(selections) = self
16514            .change_list
16515            .next_change(1, Direction::Prev)
16516            .map(|s| s.to_vec())
16517        {
16518            self.change_selections(Default::default(), window, cx, |s| {
16519                let map = s.display_snapshot();
16520                s.select_display_ranges(selections.iter().map(|a| {
16521                    let point = a.to_display_point(&map);
16522                    point..point
16523                }))
16524            })
16525        }
16526    }
16527
16528    pub fn go_to_next_document_highlight(
16529        &mut self,
16530        _: &GoToNextDocumentHighlight,
16531        window: &mut Window,
16532        cx: &mut Context<Self>,
16533    ) {
16534        self.go_to_document_highlight_before_or_after_position(Direction::Next, window, cx);
16535    }
16536
16537    pub fn go_to_prev_document_highlight(
16538        &mut self,
16539        _: &GoToPreviousDocumentHighlight,
16540        window: &mut Window,
16541        cx: &mut Context<Self>,
16542    ) {
16543        self.go_to_document_highlight_before_or_after_position(Direction::Prev, window, cx);
16544    }
16545
16546    pub fn go_to_document_highlight_before_or_after_position(
16547        &mut self,
16548        direction: Direction,
16549        window: &mut Window,
16550        cx: &mut Context<Editor>,
16551    ) {
16552        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16553        let snapshot = self.snapshot(window, cx);
16554        let buffer = &snapshot.buffer_snapshot();
16555        let position = self
16556            .selections
16557            .newest::<Point>(&snapshot.display_snapshot)
16558            .head();
16559        let anchor_position = buffer.anchor_after(position);
16560
16561        // Get all document highlights (both read and write)
16562        let mut all_highlights = Vec::new();
16563
16564        if let Some((_, read_highlights)) = self
16565            .background_highlights
16566            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
16567        {
16568            all_highlights.extend(read_highlights.iter());
16569        }
16570
16571        if let Some((_, write_highlights)) = self
16572            .background_highlights
16573            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
16574        {
16575            all_highlights.extend(write_highlights.iter());
16576        }
16577
16578        if all_highlights.is_empty() {
16579            return;
16580        }
16581
16582        // Sort highlights by position
16583        all_highlights.sort_by(|a, b| a.start.cmp(&b.start, buffer));
16584
16585        let target_highlight = match direction {
16586            Direction::Next => {
16587                // Find the first highlight after the current position
16588                all_highlights
16589                    .iter()
16590                    .find(|highlight| highlight.start.cmp(&anchor_position, buffer).is_gt())
16591            }
16592            Direction::Prev => {
16593                // Find the last highlight before the current position
16594                all_highlights
16595                    .iter()
16596                    .rev()
16597                    .find(|highlight| highlight.end.cmp(&anchor_position, buffer).is_lt())
16598            }
16599        };
16600
16601        if let Some(highlight) = target_highlight {
16602            let destination = highlight.start.to_point(buffer);
16603            let autoscroll = Autoscroll::center();
16604
16605            self.unfold_ranges(&[destination..destination], false, false, cx);
16606            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16607                s.select_ranges([destination..destination]);
16608            });
16609        }
16610    }
16611
16612    fn go_to_line<T: 'static>(
16613        &mut self,
16614        position: Anchor,
16615        highlight_color: Option<Hsla>,
16616        window: &mut Window,
16617        cx: &mut Context<Self>,
16618    ) {
16619        let snapshot = self.snapshot(window, cx).display_snapshot;
16620        let position = position.to_point(&snapshot.buffer_snapshot());
16621        let start = snapshot
16622            .buffer_snapshot()
16623            .clip_point(Point::new(position.row, 0), Bias::Left);
16624        let end = start + Point::new(1, 0);
16625        let start = snapshot.buffer_snapshot().anchor_before(start);
16626        let end = snapshot.buffer_snapshot().anchor_before(end);
16627
16628        self.highlight_rows::<T>(
16629            start..end,
16630            highlight_color
16631                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
16632            Default::default(),
16633            cx,
16634        );
16635
16636        if self.buffer.read(cx).is_singleton() {
16637            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
16638        }
16639    }
16640
16641    pub fn go_to_definition(
16642        &mut self,
16643        _: &GoToDefinition,
16644        window: &mut Window,
16645        cx: &mut Context<Self>,
16646    ) -> Task<Result<Navigated>> {
16647        let definition =
16648            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
16649        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
16650        cx.spawn_in(window, async move |editor, cx| {
16651            if definition.await? == Navigated::Yes {
16652                return Ok(Navigated::Yes);
16653            }
16654            match fallback_strategy {
16655                GoToDefinitionFallback::None => Ok(Navigated::No),
16656                GoToDefinitionFallback::FindAllReferences => {
16657                    match editor.update_in(cx, |editor, window, cx| {
16658                        editor.find_all_references(&FindAllReferences, window, cx)
16659                    })? {
16660                        Some(references) => references.await,
16661                        None => Ok(Navigated::No),
16662                    }
16663                }
16664            }
16665        })
16666    }
16667
16668    pub fn go_to_declaration(
16669        &mut self,
16670        _: &GoToDeclaration,
16671        window: &mut Window,
16672        cx: &mut Context<Self>,
16673    ) -> Task<Result<Navigated>> {
16674        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
16675    }
16676
16677    pub fn go_to_declaration_split(
16678        &mut self,
16679        _: &GoToDeclaration,
16680        window: &mut Window,
16681        cx: &mut Context<Self>,
16682    ) -> Task<Result<Navigated>> {
16683        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
16684    }
16685
16686    pub fn go_to_implementation(
16687        &mut self,
16688        _: &GoToImplementation,
16689        window: &mut Window,
16690        cx: &mut Context<Self>,
16691    ) -> Task<Result<Navigated>> {
16692        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
16693    }
16694
16695    pub fn go_to_implementation_split(
16696        &mut self,
16697        _: &GoToImplementationSplit,
16698        window: &mut Window,
16699        cx: &mut Context<Self>,
16700    ) -> Task<Result<Navigated>> {
16701        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
16702    }
16703
16704    pub fn go_to_type_definition(
16705        &mut self,
16706        _: &GoToTypeDefinition,
16707        window: &mut Window,
16708        cx: &mut Context<Self>,
16709    ) -> Task<Result<Navigated>> {
16710        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
16711    }
16712
16713    pub fn go_to_definition_split(
16714        &mut self,
16715        _: &GoToDefinitionSplit,
16716        window: &mut Window,
16717        cx: &mut Context<Self>,
16718    ) -> Task<Result<Navigated>> {
16719        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
16720    }
16721
16722    pub fn go_to_type_definition_split(
16723        &mut self,
16724        _: &GoToTypeDefinitionSplit,
16725        window: &mut Window,
16726        cx: &mut Context<Self>,
16727    ) -> Task<Result<Navigated>> {
16728        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
16729    }
16730
16731    fn go_to_definition_of_kind(
16732        &mut self,
16733        kind: GotoDefinitionKind,
16734        split: bool,
16735        window: &mut Window,
16736        cx: &mut Context<Self>,
16737    ) -> Task<Result<Navigated>> {
16738        let Some(provider) = self.semantics_provider.clone() else {
16739            return Task::ready(Ok(Navigated::No));
16740        };
16741        let head = self
16742            .selections
16743            .newest::<MultiBufferOffset>(&self.display_snapshot(cx))
16744            .head();
16745        let buffer = self.buffer.read(cx);
16746        let Some((buffer, head)) = buffer.text_anchor_for_position(head, cx) else {
16747            return Task::ready(Ok(Navigated::No));
16748        };
16749        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
16750            return Task::ready(Ok(Navigated::No));
16751        };
16752
16753        cx.spawn_in(window, async move |editor, cx| {
16754            let Some(definitions) = definitions.await? else {
16755                return Ok(Navigated::No);
16756            };
16757            let navigated = editor
16758                .update_in(cx, |editor, window, cx| {
16759                    editor.navigate_to_hover_links(
16760                        Some(kind),
16761                        definitions
16762                            .into_iter()
16763                            .filter(|location| {
16764                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
16765                            })
16766                            .map(HoverLink::Text)
16767                            .collect::<Vec<_>>(),
16768                        split,
16769                        window,
16770                        cx,
16771                    )
16772                })?
16773                .await?;
16774            anyhow::Ok(navigated)
16775        })
16776    }
16777
16778    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
16779        let selection = self.selections.newest_anchor();
16780        let head = selection.head();
16781        let tail = selection.tail();
16782
16783        let Some((buffer, start_position)) =
16784            self.buffer.read(cx).text_anchor_for_position(head, cx)
16785        else {
16786            return;
16787        };
16788
16789        let end_position = if head != tail {
16790            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
16791                return;
16792            };
16793            Some(pos)
16794        } else {
16795            None
16796        };
16797
16798        let url_finder = cx.spawn_in(window, async move |_editor, cx| {
16799            let url = if let Some(end_pos) = end_position {
16800                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
16801            } else {
16802                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
16803            };
16804
16805            if let Some(url) = url {
16806                cx.update(|window, cx| {
16807                    if parse_zed_link(&url, cx).is_some() {
16808                        window.dispatch_action(Box::new(zed_actions::OpenZedUrl { url }), cx);
16809                    } else {
16810                        cx.open_url(&url);
16811                    }
16812                })?;
16813            }
16814
16815            anyhow::Ok(())
16816        });
16817
16818        url_finder.detach();
16819    }
16820
16821    pub fn open_selected_filename(
16822        &mut self,
16823        _: &OpenSelectedFilename,
16824        window: &mut Window,
16825        cx: &mut Context<Self>,
16826    ) {
16827        let Some(workspace) = self.workspace() else {
16828            return;
16829        };
16830
16831        let position = self.selections.newest_anchor().head();
16832
16833        let Some((buffer, buffer_position)) =
16834            self.buffer.read(cx).text_anchor_for_position(position, cx)
16835        else {
16836            return;
16837        };
16838
16839        let project = self.project.clone();
16840
16841        cx.spawn_in(window, async move |_, cx| {
16842            let result = find_file(&buffer, project, buffer_position, cx).await;
16843
16844            if let Some((_, path)) = result {
16845                workspace
16846                    .update_in(cx, |workspace, window, cx| {
16847                        workspace.open_resolved_path(path, window, cx)
16848                    })?
16849                    .await?;
16850            }
16851            anyhow::Ok(())
16852        })
16853        .detach();
16854    }
16855
16856    pub(crate) fn navigate_to_hover_links(
16857        &mut self,
16858        kind: Option<GotoDefinitionKind>,
16859        definitions: Vec<HoverLink>,
16860        split: bool,
16861        window: &mut Window,
16862        cx: &mut Context<Editor>,
16863    ) -> Task<Result<Navigated>> {
16864        // Separate out url and file links, we can only handle one of them at most or an arbitrary number of locations
16865        let mut first_url_or_file = None;
16866        let definitions: Vec<_> = definitions
16867            .into_iter()
16868            .filter_map(|def| match def {
16869                HoverLink::Text(link) => Some(Task::ready(anyhow::Ok(Some(link.target)))),
16870                HoverLink::InlayHint(lsp_location, server_id) => {
16871                    let computation =
16872                        self.compute_target_location(lsp_location, server_id, window, cx);
16873                    Some(cx.background_spawn(computation))
16874                }
16875                HoverLink::Url(url) => {
16876                    first_url_or_file = Some(Either::Left(url));
16877                    None
16878                }
16879                HoverLink::File(path) => {
16880                    first_url_or_file = Some(Either::Right(path));
16881                    None
16882                }
16883            })
16884            .collect();
16885
16886        let workspace = self.workspace();
16887
16888        cx.spawn_in(window, async move |editor, cx| {
16889            let locations: Vec<Location> = future::join_all(definitions)
16890                .await
16891                .into_iter()
16892                .filter_map(|location| location.transpose())
16893                .collect::<Result<_>>()
16894                .context("location tasks")?;
16895            let mut locations = cx.update(|_, cx| {
16896                locations
16897                    .into_iter()
16898                    .map(|location| {
16899                        let buffer = location.buffer.read(cx);
16900                        (location.buffer, location.range.to_point(buffer))
16901                    })
16902                    .into_group_map()
16903            })?;
16904            let mut num_locations = 0;
16905            for ranges in locations.values_mut() {
16906                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
16907                ranges.dedup();
16908                num_locations += ranges.len();
16909            }
16910
16911            if num_locations > 1 {
16912                let Some(workspace) = workspace else {
16913                    return Ok(Navigated::No);
16914                };
16915
16916                let tab_kind = match kind {
16917                    Some(GotoDefinitionKind::Implementation) => "Implementations",
16918                    Some(GotoDefinitionKind::Symbol) | None => "Definitions",
16919                    Some(GotoDefinitionKind::Declaration) => "Declarations",
16920                    Some(GotoDefinitionKind::Type) => "Types",
16921                };
16922                let title = editor
16923                    .update_in(cx, |_, _, cx| {
16924                        let target = locations
16925                            .iter()
16926                            .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
16927                            .map(|(buffer, location)| {
16928                                buffer
16929                                    .read(cx)
16930                                    .text_for_range(location.clone())
16931                                    .collect::<String>()
16932                            })
16933                            .filter(|text| !text.contains('\n'))
16934                            .unique()
16935                            .take(3)
16936                            .join(", ");
16937                        if target.is_empty() {
16938                            tab_kind.to_owned()
16939                        } else {
16940                            format!("{tab_kind} for {target}")
16941                        }
16942                    })
16943                    .context("buffer title")?;
16944
16945                let opened = workspace
16946                    .update_in(cx, |workspace, window, cx| {
16947                        Self::open_locations_in_multibuffer(
16948                            workspace,
16949                            locations,
16950                            title,
16951                            split,
16952                            MultibufferSelectionMode::First,
16953                            window,
16954                            cx,
16955                        )
16956                    })
16957                    .is_ok();
16958
16959                anyhow::Ok(Navigated::from_bool(opened))
16960            } else if num_locations == 0 {
16961                // If there is one url or file, open it directly
16962                match first_url_or_file {
16963                    Some(Either::Left(url)) => {
16964                        cx.update(|_, cx| cx.open_url(&url))?;
16965                        Ok(Navigated::Yes)
16966                    }
16967                    Some(Either::Right(path)) => {
16968                        let Some(workspace) = workspace else {
16969                            return Ok(Navigated::No);
16970                        };
16971
16972                        workspace
16973                            .update_in(cx, |workspace, window, cx| {
16974                                workspace.open_resolved_path(path, window, cx)
16975                            })?
16976                            .await?;
16977                        Ok(Navigated::Yes)
16978                    }
16979                    None => Ok(Navigated::No),
16980                }
16981            } else {
16982                let Some(workspace) = workspace else {
16983                    return Ok(Navigated::No);
16984                };
16985
16986                let (target_buffer, target_ranges) = locations.into_iter().next().unwrap();
16987                let target_range = target_ranges.first().unwrap().clone();
16988
16989                editor.update_in(cx, |editor, window, cx| {
16990                    let range = target_range.to_point(target_buffer.read(cx));
16991                    let range = editor.range_for_match(&range);
16992                    let range = collapse_multiline_range(range);
16993
16994                    if !split
16995                        && Some(&target_buffer) == editor.buffer.read(cx).as_singleton().as_ref()
16996                    {
16997                        editor.go_to_singleton_buffer_range(range, window, cx);
16998                    } else {
16999                        let pane = workspace.read(cx).active_pane().clone();
17000                        window.defer(cx, move |window, cx| {
17001                            let target_editor: Entity<Self> =
17002                                workspace.update(cx, |workspace, cx| {
17003                                    let pane = if split {
17004                                        workspace.adjacent_pane(window, cx)
17005                                    } else {
17006                                        workspace.active_pane().clone()
17007                                    };
17008
17009                                    workspace.open_project_item(
17010                                        pane,
17011                                        target_buffer.clone(),
17012                                        true,
17013                                        true,
17014                                        window,
17015                                        cx,
17016                                    )
17017                                });
17018                            target_editor.update(cx, |target_editor, cx| {
17019                                // When selecting a definition in a different buffer, disable the nav history
17020                                // to avoid creating a history entry at the previous cursor location.
17021                                pane.update(cx, |pane, _| pane.disable_history());
17022                                target_editor.go_to_singleton_buffer_range(range, window, cx);
17023                                pane.update(cx, |pane, _| pane.enable_history());
17024                            });
17025                        });
17026                    }
17027                    Navigated::Yes
17028                })
17029            }
17030        })
17031    }
17032
17033    fn compute_target_location(
17034        &self,
17035        lsp_location: lsp::Location,
17036        server_id: LanguageServerId,
17037        window: &mut Window,
17038        cx: &mut Context<Self>,
17039    ) -> Task<anyhow::Result<Option<Location>>> {
17040        let Some(project) = self.project.clone() else {
17041            return Task::ready(Ok(None));
17042        };
17043
17044        cx.spawn_in(window, async move |editor, cx| {
17045            let location_task = editor.update(cx, |_, cx| {
17046                project.update(cx, |project, cx| {
17047                    project.open_local_buffer_via_lsp(lsp_location.uri.clone(), server_id, cx)
17048                })
17049            })?;
17050            let location = Some({
17051                let target_buffer_handle = location_task.await.context("open local buffer")?;
17052                let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
17053                    let target_start = target_buffer
17054                        .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
17055                    let target_end = target_buffer
17056                        .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
17057                    target_buffer.anchor_after(target_start)
17058                        ..target_buffer.anchor_before(target_end)
17059                })?;
17060                Location {
17061                    buffer: target_buffer_handle,
17062                    range,
17063                }
17064            });
17065            Ok(location)
17066        })
17067    }
17068
17069    fn go_to_next_reference(
17070        &mut self,
17071        _: &GoToNextReference,
17072        window: &mut Window,
17073        cx: &mut Context<Self>,
17074    ) {
17075        let task = self.go_to_reference_before_or_after_position(Direction::Next, 1, window, cx);
17076        if let Some(task) = task {
17077            task.detach();
17078        };
17079    }
17080
17081    fn go_to_prev_reference(
17082        &mut self,
17083        _: &GoToPreviousReference,
17084        window: &mut Window,
17085        cx: &mut Context<Self>,
17086    ) {
17087        let task = self.go_to_reference_before_or_after_position(Direction::Prev, 1, window, cx);
17088        if let Some(task) = task {
17089            task.detach();
17090        };
17091    }
17092
17093    pub fn go_to_reference_before_or_after_position(
17094        &mut self,
17095        direction: Direction,
17096        count: usize,
17097        window: &mut Window,
17098        cx: &mut Context<Self>,
17099    ) -> Option<Task<Result<()>>> {
17100        let selection = self.selections.newest_anchor();
17101        let head = selection.head();
17102
17103        let multi_buffer = self.buffer.read(cx);
17104
17105        let (buffer, text_head) = multi_buffer.text_anchor_for_position(head, cx)?;
17106        let workspace = self.workspace()?;
17107        let project = workspace.read(cx).project().clone();
17108        let references =
17109            project.update(cx, |project, cx| project.references(&buffer, text_head, cx));
17110        Some(cx.spawn_in(window, async move |editor, cx| -> Result<()> {
17111            let Some(locations) = references.await? else {
17112                return Ok(());
17113            };
17114
17115            if locations.is_empty() {
17116                // totally normal - the cursor may be on something which is not
17117                // a symbol (e.g. a keyword)
17118                log::info!("no references found under cursor");
17119                return Ok(());
17120            }
17121
17122            let multi_buffer = editor.read_with(cx, |editor, _| editor.buffer().clone())?;
17123
17124            let multi_buffer_snapshot =
17125                multi_buffer.read_with(cx, |multi_buffer, cx| multi_buffer.snapshot(cx))?;
17126
17127            let (locations, current_location_index) =
17128                multi_buffer.update(cx, |multi_buffer, cx| {
17129                    let mut locations = locations
17130                        .into_iter()
17131                        .filter_map(|loc| {
17132                            let start = multi_buffer.buffer_anchor_to_anchor(
17133                                &loc.buffer,
17134                                loc.range.start,
17135                                cx,
17136                            )?;
17137                            let end = multi_buffer.buffer_anchor_to_anchor(
17138                                &loc.buffer,
17139                                loc.range.end,
17140                                cx,
17141                            )?;
17142                            Some(start..end)
17143                        })
17144                        .collect::<Vec<_>>();
17145
17146                    // There is an O(n) implementation, but given this list will be
17147                    // small (usually <100 items), the extra O(log(n)) factor isn't
17148                    // worth the (surprisingly large amount of) extra complexity.
17149                    locations
17150                        .sort_unstable_by(|l, r| l.start.cmp(&r.start, &multi_buffer_snapshot));
17151
17152                    let head_offset = head.to_offset(&multi_buffer_snapshot);
17153
17154                    let current_location_index = locations.iter().position(|loc| {
17155                        loc.start.to_offset(&multi_buffer_snapshot) <= head_offset
17156                            && loc.end.to_offset(&multi_buffer_snapshot) >= head_offset
17157                    });
17158
17159                    (locations, current_location_index)
17160                })?;
17161
17162            let Some(current_location_index) = current_location_index else {
17163                // This indicates something has gone wrong, because we already
17164                // handle the "no references" case above
17165                log::error!(
17166                    "failed to find current reference under cursor. Total references: {}",
17167                    locations.len()
17168                );
17169                return Ok(());
17170            };
17171
17172            let destination_location_index = match direction {
17173                Direction::Next => (current_location_index + count) % locations.len(),
17174                Direction::Prev => {
17175                    (current_location_index + locations.len() - count % locations.len())
17176                        % locations.len()
17177                }
17178            };
17179
17180            // TODO(cameron): is this needed?
17181            // the thinking is to avoid "jumping to the current location" (avoid
17182            // polluting "jumplist" in vim terms)
17183            if current_location_index == destination_location_index {
17184                return Ok(());
17185            }
17186
17187            let Range { start, end } = locations[destination_location_index];
17188
17189            editor.update_in(cx, |editor, window, cx| {
17190                let effects = SelectionEffects::default();
17191
17192                editor.unfold_ranges(&[start..end], false, false, cx);
17193                editor.change_selections(effects, window, cx, |s| {
17194                    s.select_ranges([start..start]);
17195                });
17196            })?;
17197
17198            Ok(())
17199        }))
17200    }
17201
17202    pub fn find_all_references(
17203        &mut self,
17204        _: &FindAllReferences,
17205        window: &mut Window,
17206        cx: &mut Context<Self>,
17207    ) -> Option<Task<Result<Navigated>>> {
17208        let selection = self
17209            .selections
17210            .newest::<MultiBufferOffset>(&self.display_snapshot(cx));
17211        let multi_buffer = self.buffer.read(cx);
17212        let head = selection.head();
17213
17214        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
17215        let head_anchor = multi_buffer_snapshot.anchor_at(
17216            head,
17217            if head < selection.tail() {
17218                Bias::Right
17219            } else {
17220                Bias::Left
17221            },
17222        );
17223
17224        match self
17225            .find_all_references_task_sources
17226            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
17227        {
17228            Ok(_) => {
17229                log::info!(
17230                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
17231                );
17232                return None;
17233            }
17234            Err(i) => {
17235                self.find_all_references_task_sources.insert(i, head_anchor);
17236            }
17237        }
17238
17239        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
17240        let workspace = self.workspace()?;
17241        let project = workspace.read(cx).project().clone();
17242        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
17243        Some(cx.spawn_in(window, async move |editor, cx| {
17244            let _cleanup = cx.on_drop(&editor, move |editor, _| {
17245                if let Ok(i) = editor
17246                    .find_all_references_task_sources
17247                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
17248                {
17249                    editor.find_all_references_task_sources.remove(i);
17250                }
17251            });
17252
17253            let Some(locations) = references.await? else {
17254                return anyhow::Ok(Navigated::No);
17255            };
17256            let mut locations = cx.update(|_, cx| {
17257                locations
17258                    .into_iter()
17259                    .map(|location| {
17260                        let buffer = location.buffer.read(cx);
17261                        (location.buffer, location.range.to_point(buffer))
17262                    })
17263                    .into_group_map()
17264            })?;
17265            if locations.is_empty() {
17266                return anyhow::Ok(Navigated::No);
17267            }
17268            for ranges in locations.values_mut() {
17269                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
17270                ranges.dedup();
17271            }
17272
17273            workspace.update_in(cx, |workspace, window, cx| {
17274                let target = locations
17275                    .iter()
17276                    .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
17277                    .map(|(buffer, location)| {
17278                        buffer
17279                            .read(cx)
17280                            .text_for_range(location.clone())
17281                            .collect::<String>()
17282                    })
17283                    .filter(|text| !text.contains('\n'))
17284                    .unique()
17285                    .take(3)
17286                    .join(", ");
17287                let title = if target.is_empty() {
17288                    "References".to_owned()
17289                } else {
17290                    format!("References to {target}")
17291                };
17292                Self::open_locations_in_multibuffer(
17293                    workspace,
17294                    locations,
17295                    title,
17296                    false,
17297                    MultibufferSelectionMode::First,
17298                    window,
17299                    cx,
17300                );
17301                Navigated::Yes
17302            })
17303        }))
17304    }
17305
17306    /// Opens a multibuffer with the given project locations in it
17307    pub fn open_locations_in_multibuffer(
17308        workspace: &mut Workspace,
17309        locations: std::collections::HashMap<Entity<Buffer>, Vec<Range<Point>>>,
17310        title: String,
17311        split: bool,
17312        multibuffer_selection_mode: MultibufferSelectionMode,
17313        window: &mut Window,
17314        cx: &mut Context<Workspace>,
17315    ) {
17316        if locations.is_empty() {
17317            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
17318            return;
17319        }
17320
17321        let capability = workspace.project().read(cx).capability();
17322        let mut ranges = <Vec<Range<Anchor>>>::new();
17323
17324        // a key to find existing multibuffer editors with the same set of locations
17325        // to prevent us from opening more and more multibuffer tabs for searches and the like
17326        let mut key = (title.clone(), vec![]);
17327        let excerpt_buffer = cx.new(|cx| {
17328            let key = &mut key.1;
17329            let mut multibuffer = MultiBuffer::new(capability);
17330            for (buffer, mut ranges_for_buffer) in locations {
17331                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
17332                key.push((buffer.read(cx).remote_id(), ranges_for_buffer.clone()));
17333                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
17334                    PathKey::for_buffer(&buffer, cx),
17335                    buffer.clone(),
17336                    ranges_for_buffer,
17337                    multibuffer_context_lines(cx),
17338                    cx,
17339                );
17340                ranges.extend(new_ranges)
17341            }
17342
17343            multibuffer.with_title(title)
17344        });
17345        let existing = workspace.active_pane().update(cx, |pane, cx| {
17346            pane.items()
17347                .filter_map(|item| item.downcast::<Editor>())
17348                .find(|editor| {
17349                    editor
17350                        .read(cx)
17351                        .lookup_key
17352                        .as_ref()
17353                        .and_then(|it| {
17354                            it.downcast_ref::<(String, Vec<(BufferId, Vec<Range<Point>>)>)>()
17355                        })
17356                        .is_some_and(|it| *it == key)
17357                })
17358        });
17359        let editor = existing.unwrap_or_else(|| {
17360            cx.new(|cx| {
17361                let mut editor = Editor::for_multibuffer(
17362                    excerpt_buffer,
17363                    Some(workspace.project().clone()),
17364                    window,
17365                    cx,
17366                );
17367                editor.lookup_key = Some(Box::new(key));
17368                editor
17369            })
17370        });
17371        editor.update(cx, |editor, cx| match multibuffer_selection_mode {
17372            MultibufferSelectionMode::First => {
17373                if let Some(first_range) = ranges.first() {
17374                    editor.change_selections(
17375                        SelectionEffects::no_scroll(),
17376                        window,
17377                        cx,
17378                        |selections| {
17379                            selections.clear_disjoint();
17380                            selections.select_anchor_ranges(std::iter::once(first_range.clone()));
17381                        },
17382                    );
17383                }
17384                editor.highlight_background::<Self>(
17385                    &ranges,
17386                    |theme| theme.colors().editor_highlighted_line_background,
17387                    cx,
17388                );
17389            }
17390            MultibufferSelectionMode::All => {
17391                editor.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
17392                    selections.clear_disjoint();
17393                    selections.select_anchor_ranges(ranges);
17394                });
17395            }
17396        });
17397
17398        let item = Box::new(editor);
17399        let item_id = item.item_id();
17400
17401        if split {
17402            let pane = workspace.adjacent_pane(window, cx);
17403            workspace.add_item(pane, item, None, true, true, window, cx);
17404        } else if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
17405            let (preview_item_id, preview_item_idx) =
17406                workspace.active_pane().read_with(cx, |pane, _| {
17407                    (pane.preview_item_id(), pane.preview_item_idx())
17408                });
17409
17410            workspace.add_item_to_active_pane(item, preview_item_idx, true, window, cx);
17411
17412            if let Some(preview_item_id) = preview_item_id {
17413                workspace.active_pane().update(cx, |pane, cx| {
17414                    pane.remove_item(preview_item_id, false, false, window, cx);
17415                });
17416            }
17417        } else {
17418            workspace.add_item_to_active_pane(item, None, true, window, cx);
17419        }
17420        workspace.active_pane().update(cx, |pane, cx| {
17421            pane.set_preview_item_id(Some(item_id), cx);
17422        });
17423    }
17424
17425    pub fn rename(
17426        &mut self,
17427        _: &Rename,
17428        window: &mut Window,
17429        cx: &mut Context<Self>,
17430    ) -> Option<Task<Result<()>>> {
17431        use language::ToOffset as _;
17432
17433        let provider = self.semantics_provider.clone()?;
17434        let selection = self.selections.newest_anchor().clone();
17435        let (cursor_buffer, cursor_buffer_position) = self
17436            .buffer
17437            .read(cx)
17438            .text_anchor_for_position(selection.head(), cx)?;
17439        let (tail_buffer, cursor_buffer_position_end) = self
17440            .buffer
17441            .read(cx)
17442            .text_anchor_for_position(selection.tail(), cx)?;
17443        if tail_buffer != cursor_buffer {
17444            return None;
17445        }
17446
17447        let snapshot = cursor_buffer.read(cx).snapshot();
17448        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
17449        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
17450        let prepare_rename = provider
17451            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
17452            .unwrap_or_else(|| Task::ready(Ok(None)));
17453        drop(snapshot);
17454
17455        Some(cx.spawn_in(window, async move |this, cx| {
17456            let rename_range = if let Some(range) = prepare_rename.await? {
17457                Some(range)
17458            } else {
17459                this.update(cx, |this, cx| {
17460                    let buffer = this.buffer.read(cx).snapshot(cx);
17461                    let mut buffer_highlights = this
17462                        .document_highlights_for_position(selection.head(), &buffer)
17463                        .filter(|highlight| {
17464                            highlight.start.excerpt_id == selection.head().excerpt_id
17465                                && highlight.end.excerpt_id == selection.head().excerpt_id
17466                        });
17467                    buffer_highlights
17468                        .next()
17469                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
17470                })?
17471            };
17472            if let Some(rename_range) = rename_range {
17473                this.update_in(cx, |this, window, cx| {
17474                    let snapshot = cursor_buffer.read(cx).snapshot();
17475                    let rename_buffer_range = rename_range.to_offset(&snapshot);
17476                    let cursor_offset_in_rename_range =
17477                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
17478                    let cursor_offset_in_rename_range_end =
17479                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
17480
17481                    this.take_rename(false, window, cx);
17482                    let buffer = this.buffer.read(cx).read(cx);
17483                    let cursor_offset = selection.head().to_offset(&buffer);
17484                    let rename_start =
17485                        cursor_offset.saturating_sub_usize(cursor_offset_in_rename_range);
17486                    let rename_end = rename_start + rename_buffer_range.len();
17487                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
17488                    let mut old_highlight_id = None;
17489                    let old_name: Arc<str> = buffer
17490                        .chunks(rename_start..rename_end, true)
17491                        .map(|chunk| {
17492                            if old_highlight_id.is_none() {
17493                                old_highlight_id = chunk.syntax_highlight_id;
17494                            }
17495                            chunk.text
17496                        })
17497                        .collect::<String>()
17498                        .into();
17499
17500                    drop(buffer);
17501
17502                    // Position the selection in the rename editor so that it matches the current selection.
17503                    this.show_local_selections = false;
17504                    let rename_editor = cx.new(|cx| {
17505                        let mut editor = Editor::single_line(window, cx);
17506                        editor.buffer.update(cx, |buffer, cx| {
17507                            buffer.edit(
17508                                [(MultiBufferOffset(0)..MultiBufferOffset(0), old_name.clone())],
17509                                None,
17510                                cx,
17511                            )
17512                        });
17513                        let cursor_offset_in_rename_range =
17514                            MultiBufferOffset(cursor_offset_in_rename_range);
17515                        let cursor_offset_in_rename_range_end =
17516                            MultiBufferOffset(cursor_offset_in_rename_range_end);
17517                        let rename_selection_range = match cursor_offset_in_rename_range
17518                            .cmp(&cursor_offset_in_rename_range_end)
17519                        {
17520                            Ordering::Equal => {
17521                                editor.select_all(&SelectAll, window, cx);
17522                                return editor;
17523                            }
17524                            Ordering::Less => {
17525                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
17526                            }
17527                            Ordering::Greater => {
17528                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
17529                            }
17530                        };
17531                        if rename_selection_range.end.0 > old_name.len() {
17532                            editor.select_all(&SelectAll, window, cx);
17533                        } else {
17534                            editor.change_selections(Default::default(), window, cx, |s| {
17535                                s.select_ranges([rename_selection_range]);
17536                            });
17537                        }
17538                        editor
17539                    });
17540                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
17541                        if e == &EditorEvent::Focused {
17542                            cx.emit(EditorEvent::FocusedIn)
17543                        }
17544                    })
17545                    .detach();
17546
17547                    let write_highlights =
17548                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
17549                    let read_highlights =
17550                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
17551                    let ranges = write_highlights
17552                        .iter()
17553                        .flat_map(|(_, ranges)| ranges.iter())
17554                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
17555                        .cloned()
17556                        .collect();
17557
17558                    this.highlight_text::<Rename>(
17559                        ranges,
17560                        HighlightStyle {
17561                            fade_out: Some(0.6),
17562                            ..Default::default()
17563                        },
17564                        cx,
17565                    );
17566                    let rename_focus_handle = rename_editor.focus_handle(cx);
17567                    window.focus(&rename_focus_handle);
17568                    let block_id = this.insert_blocks(
17569                        [BlockProperties {
17570                            style: BlockStyle::Flex,
17571                            placement: BlockPlacement::Below(range.start),
17572                            height: Some(1),
17573                            render: Arc::new({
17574                                let rename_editor = rename_editor.clone();
17575                                move |cx: &mut BlockContext| {
17576                                    let mut text_style = cx.editor_style.text.clone();
17577                                    if let Some(highlight_style) = old_highlight_id
17578                                        .and_then(|h| h.style(&cx.editor_style.syntax))
17579                                    {
17580                                        text_style = text_style.highlight(highlight_style);
17581                                    }
17582                                    div()
17583                                        .block_mouse_except_scroll()
17584                                        .pl(cx.anchor_x)
17585                                        .child(EditorElement::new(
17586                                            &rename_editor,
17587                                            EditorStyle {
17588                                                background: cx.theme().system().transparent,
17589                                                local_player: cx.editor_style.local_player,
17590                                                text: text_style,
17591                                                scrollbar_width: cx.editor_style.scrollbar_width,
17592                                                syntax: cx.editor_style.syntax.clone(),
17593                                                status: cx.editor_style.status.clone(),
17594                                                inlay_hints_style: HighlightStyle {
17595                                                    font_weight: Some(FontWeight::BOLD),
17596                                                    ..make_inlay_hints_style(cx.app)
17597                                                },
17598                                                edit_prediction_styles: make_suggestion_styles(
17599                                                    cx.app,
17600                                                ),
17601                                                ..EditorStyle::default()
17602                                            },
17603                                        ))
17604                                        .into_any_element()
17605                                }
17606                            }),
17607                            priority: 0,
17608                        }],
17609                        Some(Autoscroll::fit()),
17610                        cx,
17611                    )[0];
17612                    this.pending_rename = Some(RenameState {
17613                        range,
17614                        old_name,
17615                        editor: rename_editor,
17616                        block_id,
17617                    });
17618                })?;
17619            }
17620
17621            Ok(())
17622        }))
17623    }
17624
17625    pub fn confirm_rename(
17626        &mut self,
17627        _: &ConfirmRename,
17628        window: &mut Window,
17629        cx: &mut Context<Self>,
17630    ) -> Option<Task<Result<()>>> {
17631        let rename = self.take_rename(false, window, cx)?;
17632        let workspace = self.workspace()?.downgrade();
17633        let (buffer, start) = self
17634            .buffer
17635            .read(cx)
17636            .text_anchor_for_position(rename.range.start, cx)?;
17637        let (end_buffer, _) = self
17638            .buffer
17639            .read(cx)
17640            .text_anchor_for_position(rename.range.end, cx)?;
17641        if buffer != end_buffer {
17642            return None;
17643        }
17644
17645        let old_name = rename.old_name;
17646        let new_name = rename.editor.read(cx).text(cx);
17647
17648        let rename = self.semantics_provider.as_ref()?.perform_rename(
17649            &buffer,
17650            start,
17651            new_name.clone(),
17652            cx,
17653        )?;
17654
17655        Some(cx.spawn_in(window, async move |editor, cx| {
17656            let project_transaction = rename.await?;
17657            Self::open_project_transaction(
17658                &editor,
17659                workspace,
17660                project_transaction,
17661                format!("Rename: {}{}", old_name, new_name),
17662                cx,
17663            )
17664            .await?;
17665
17666            editor.update(cx, |editor, cx| {
17667                editor.refresh_document_highlights(cx);
17668            })?;
17669            Ok(())
17670        }))
17671    }
17672
17673    fn take_rename(
17674        &mut self,
17675        moving_cursor: bool,
17676        window: &mut Window,
17677        cx: &mut Context<Self>,
17678    ) -> Option<RenameState> {
17679        let rename = self.pending_rename.take()?;
17680        if rename.editor.focus_handle(cx).is_focused(window) {
17681            window.focus(&self.focus_handle);
17682        }
17683
17684        self.remove_blocks(
17685            [rename.block_id].into_iter().collect(),
17686            Some(Autoscroll::fit()),
17687            cx,
17688        );
17689        self.clear_highlights::<Rename>(cx);
17690        self.show_local_selections = true;
17691
17692        if moving_cursor {
17693            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
17694                editor
17695                    .selections
17696                    .newest::<MultiBufferOffset>(&editor.display_snapshot(cx))
17697                    .head()
17698            });
17699
17700            // Update the selection to match the position of the selection inside
17701            // the rename editor.
17702            let snapshot = self.buffer.read(cx).read(cx);
17703            let rename_range = rename.range.to_offset(&snapshot);
17704            let cursor_in_editor = snapshot
17705                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
17706                .min(rename_range.end);
17707            drop(snapshot);
17708
17709            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17710                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
17711            });
17712        } else {
17713            self.refresh_document_highlights(cx);
17714        }
17715
17716        Some(rename)
17717    }
17718
17719    pub fn pending_rename(&self) -> Option<&RenameState> {
17720        self.pending_rename.as_ref()
17721    }
17722
17723    fn format(
17724        &mut self,
17725        _: &Format,
17726        window: &mut Window,
17727        cx: &mut Context<Self>,
17728    ) -> Option<Task<Result<()>>> {
17729        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17730
17731        let project = match &self.project {
17732            Some(project) => project.clone(),
17733            None => return None,
17734        };
17735
17736        Some(self.perform_format(
17737            project,
17738            FormatTrigger::Manual,
17739            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
17740            window,
17741            cx,
17742        ))
17743    }
17744
17745    fn format_selections(
17746        &mut self,
17747        _: &FormatSelections,
17748        window: &mut Window,
17749        cx: &mut Context<Self>,
17750    ) -> Option<Task<Result<()>>> {
17751        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17752
17753        let project = match &self.project {
17754            Some(project) => project.clone(),
17755            None => return None,
17756        };
17757
17758        let ranges = self
17759            .selections
17760            .all_adjusted(&self.display_snapshot(cx))
17761            .into_iter()
17762            .map(|selection| selection.range())
17763            .collect_vec();
17764
17765        Some(self.perform_format(
17766            project,
17767            FormatTrigger::Manual,
17768            FormatTarget::Ranges(ranges),
17769            window,
17770            cx,
17771        ))
17772    }
17773
17774    fn perform_format(
17775        &mut self,
17776        project: Entity<Project>,
17777        trigger: FormatTrigger,
17778        target: FormatTarget,
17779        window: &mut Window,
17780        cx: &mut Context<Self>,
17781    ) -> Task<Result<()>> {
17782        let buffer = self.buffer.clone();
17783        let (buffers, target) = match target {
17784            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
17785            FormatTarget::Ranges(selection_ranges) => {
17786                let multi_buffer = buffer.read(cx);
17787                let snapshot = multi_buffer.read(cx);
17788                let mut buffers = HashSet::default();
17789                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
17790                    BTreeMap::new();
17791                for selection_range in selection_ranges {
17792                    for (buffer, buffer_range, _) in
17793                        snapshot.range_to_buffer_ranges(selection_range)
17794                    {
17795                        let buffer_id = buffer.remote_id();
17796                        let start = buffer.anchor_before(buffer_range.start);
17797                        let end = buffer.anchor_after(buffer_range.end);
17798                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
17799                        buffer_id_to_ranges
17800                            .entry(buffer_id)
17801                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
17802                            .or_insert_with(|| vec![start..end]);
17803                    }
17804                }
17805                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
17806            }
17807        };
17808
17809        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
17810        let selections_prev = transaction_id_prev
17811            .and_then(|transaction_id_prev| {
17812                // default to selections as they were after the last edit, if we have them,
17813                // instead of how they are now.
17814                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
17815                // will take you back to where you made the last edit, instead of staying where you scrolled
17816                self.selection_history
17817                    .transaction(transaction_id_prev)
17818                    .map(|t| t.0.clone())
17819            })
17820            .unwrap_or_else(|| self.selections.disjoint_anchors_arc());
17821
17822        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
17823        let format = project.update(cx, |project, cx| {
17824            project.format(buffers, target, true, trigger, cx)
17825        });
17826
17827        cx.spawn_in(window, async move |editor, cx| {
17828            let transaction = futures::select_biased! {
17829                transaction = format.log_err().fuse() => transaction,
17830                () = timeout => {
17831                    log::warn!("timed out waiting for formatting");
17832                    None
17833                }
17834            };
17835
17836            buffer
17837                .update(cx, |buffer, cx| {
17838                    if let Some(transaction) = transaction
17839                        && !buffer.is_singleton()
17840                    {
17841                        buffer.push_transaction(&transaction.0, cx);
17842                    }
17843                    cx.notify();
17844                })
17845                .ok();
17846
17847            if let Some(transaction_id_now) =
17848                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
17849            {
17850                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
17851                if has_new_transaction {
17852                    _ = editor.update(cx, |editor, _| {
17853                        editor
17854                            .selection_history
17855                            .insert_transaction(transaction_id_now, selections_prev);
17856                    });
17857                }
17858            }
17859
17860            Ok(())
17861        })
17862    }
17863
17864    fn organize_imports(
17865        &mut self,
17866        _: &OrganizeImports,
17867        window: &mut Window,
17868        cx: &mut Context<Self>,
17869    ) -> Option<Task<Result<()>>> {
17870        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17871        let project = match &self.project {
17872            Some(project) => project.clone(),
17873            None => return None,
17874        };
17875        Some(self.perform_code_action_kind(
17876            project,
17877            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
17878            window,
17879            cx,
17880        ))
17881    }
17882
17883    fn perform_code_action_kind(
17884        &mut self,
17885        project: Entity<Project>,
17886        kind: CodeActionKind,
17887        window: &mut Window,
17888        cx: &mut Context<Self>,
17889    ) -> Task<Result<()>> {
17890        let buffer = self.buffer.clone();
17891        let buffers = buffer.read(cx).all_buffers();
17892        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
17893        let apply_action = project.update(cx, |project, cx| {
17894            project.apply_code_action_kind(buffers, kind, true, cx)
17895        });
17896        cx.spawn_in(window, async move |_, cx| {
17897            let transaction = futures::select_biased! {
17898                () = timeout => {
17899                    log::warn!("timed out waiting for executing code action");
17900                    None
17901                }
17902                transaction = apply_action.log_err().fuse() => transaction,
17903            };
17904            buffer
17905                .update(cx, |buffer, cx| {
17906                    // check if we need this
17907                    if let Some(transaction) = transaction
17908                        && !buffer.is_singleton()
17909                    {
17910                        buffer.push_transaction(&transaction.0, cx);
17911                    }
17912                    cx.notify();
17913                })
17914                .ok();
17915            Ok(())
17916        })
17917    }
17918
17919    pub fn restart_language_server(
17920        &mut self,
17921        _: &RestartLanguageServer,
17922        _: &mut Window,
17923        cx: &mut Context<Self>,
17924    ) {
17925        if let Some(project) = self.project.clone() {
17926            self.buffer.update(cx, |multi_buffer, cx| {
17927                project.update(cx, |project, cx| {
17928                    project.restart_language_servers_for_buffers(
17929                        multi_buffer.all_buffers().into_iter().collect(),
17930                        HashSet::default(),
17931                        cx,
17932                    );
17933                });
17934            })
17935        }
17936    }
17937
17938    pub fn stop_language_server(
17939        &mut self,
17940        _: &StopLanguageServer,
17941        _: &mut Window,
17942        cx: &mut Context<Self>,
17943    ) {
17944        if let Some(project) = self.project.clone() {
17945            self.buffer.update(cx, |multi_buffer, cx| {
17946                project.update(cx, |project, cx| {
17947                    project.stop_language_servers_for_buffers(
17948                        multi_buffer.all_buffers().into_iter().collect(),
17949                        HashSet::default(),
17950                        cx,
17951                    );
17952                });
17953            });
17954            self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
17955        }
17956    }
17957
17958    fn cancel_language_server_work(
17959        workspace: &mut Workspace,
17960        _: &actions::CancelLanguageServerWork,
17961        _: &mut Window,
17962        cx: &mut Context<Workspace>,
17963    ) {
17964        let project = workspace.project();
17965        let buffers = workspace
17966            .active_item(cx)
17967            .and_then(|item| item.act_as::<Editor>(cx))
17968            .map_or(HashSet::default(), |editor| {
17969                editor.read(cx).buffer.read(cx).all_buffers()
17970            });
17971        project.update(cx, |project, cx| {
17972            project.cancel_language_server_work_for_buffers(buffers, cx);
17973        });
17974    }
17975
17976    fn show_character_palette(
17977        &mut self,
17978        _: &ShowCharacterPalette,
17979        window: &mut Window,
17980        _: &mut Context<Self>,
17981    ) {
17982        window.show_character_palette();
17983    }
17984
17985    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
17986        if !self.diagnostics_enabled() {
17987            return;
17988        }
17989
17990        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
17991            let buffer = self.buffer.read(cx).snapshot(cx);
17992            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
17993            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
17994            let is_valid = buffer
17995                .diagnostics_in_range::<MultiBufferOffset>(primary_range_start..primary_range_end)
17996                .any(|entry| {
17997                    entry.diagnostic.is_primary
17998                        && !entry.range.is_empty()
17999                        && entry.range.start == primary_range_start
18000                        && entry.diagnostic.message == active_diagnostics.active_message
18001                });
18002
18003            if !is_valid {
18004                self.dismiss_diagnostics(cx);
18005            }
18006        }
18007    }
18008
18009    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
18010        match &self.active_diagnostics {
18011            ActiveDiagnostic::Group(group) => Some(group),
18012            _ => None,
18013        }
18014    }
18015
18016    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
18017        if !self.diagnostics_enabled() {
18018            return;
18019        }
18020        self.dismiss_diagnostics(cx);
18021        self.active_diagnostics = ActiveDiagnostic::All;
18022    }
18023
18024    fn activate_diagnostics(
18025        &mut self,
18026        buffer_id: BufferId,
18027        diagnostic: DiagnosticEntryRef<'_, MultiBufferOffset>,
18028        window: &mut Window,
18029        cx: &mut Context<Self>,
18030    ) {
18031        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
18032            return;
18033        }
18034        self.dismiss_diagnostics(cx);
18035        let snapshot = self.snapshot(window, cx);
18036        let buffer = self.buffer.read(cx).snapshot(cx);
18037        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
18038            return;
18039        };
18040
18041        let diagnostic_group = buffer
18042            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
18043            .collect::<Vec<_>>();
18044
18045        let language_registry = self
18046            .project()
18047            .map(|project| project.read(cx).languages().clone());
18048
18049        let blocks = renderer.render_group(
18050            diagnostic_group,
18051            buffer_id,
18052            snapshot,
18053            cx.weak_entity(),
18054            language_registry,
18055            cx,
18056        );
18057
18058        let blocks = self.display_map.update(cx, |display_map, cx| {
18059            display_map.insert_blocks(blocks, cx).into_iter().collect()
18060        });
18061        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
18062            active_range: buffer.anchor_before(diagnostic.range.start)
18063                ..buffer.anchor_after(diagnostic.range.end),
18064            active_message: diagnostic.diagnostic.message.clone(),
18065            group_id: diagnostic.diagnostic.group_id,
18066            blocks,
18067        });
18068        cx.notify();
18069    }
18070
18071    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
18072        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
18073            return;
18074        };
18075
18076        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
18077        if let ActiveDiagnostic::Group(group) = prev {
18078            self.display_map.update(cx, |display_map, cx| {
18079                display_map.remove_blocks(group.blocks, cx);
18080            });
18081            cx.notify();
18082        }
18083    }
18084
18085    /// Disable inline diagnostics rendering for this editor.
18086    pub fn disable_inline_diagnostics(&mut self) {
18087        self.inline_diagnostics_enabled = false;
18088        self.inline_diagnostics_update = Task::ready(());
18089        self.inline_diagnostics.clear();
18090    }
18091
18092    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
18093        self.diagnostics_enabled = false;
18094        self.dismiss_diagnostics(cx);
18095        self.inline_diagnostics_update = Task::ready(());
18096        self.inline_diagnostics.clear();
18097    }
18098
18099    pub fn disable_word_completions(&mut self) {
18100        self.word_completions_enabled = false;
18101    }
18102
18103    pub fn diagnostics_enabled(&self) -> bool {
18104        self.diagnostics_enabled && self.mode.is_full()
18105    }
18106
18107    pub fn inline_diagnostics_enabled(&self) -> bool {
18108        self.inline_diagnostics_enabled && self.diagnostics_enabled()
18109    }
18110
18111    pub fn show_inline_diagnostics(&self) -> bool {
18112        self.show_inline_diagnostics
18113    }
18114
18115    pub fn toggle_inline_diagnostics(
18116        &mut self,
18117        _: &ToggleInlineDiagnostics,
18118        window: &mut Window,
18119        cx: &mut Context<Editor>,
18120    ) {
18121        self.show_inline_diagnostics = !self.show_inline_diagnostics;
18122        self.refresh_inline_diagnostics(false, window, cx);
18123    }
18124
18125    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
18126        self.diagnostics_max_severity = severity;
18127        self.display_map.update(cx, |display_map, _| {
18128            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
18129        });
18130    }
18131
18132    pub fn toggle_diagnostics(
18133        &mut self,
18134        _: &ToggleDiagnostics,
18135        window: &mut Window,
18136        cx: &mut Context<Editor>,
18137    ) {
18138        if !self.diagnostics_enabled() {
18139            return;
18140        }
18141
18142        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
18143            EditorSettings::get_global(cx)
18144                .diagnostics_max_severity
18145                .filter(|severity| severity != &DiagnosticSeverity::Off)
18146                .unwrap_or(DiagnosticSeverity::Hint)
18147        } else {
18148            DiagnosticSeverity::Off
18149        };
18150        self.set_max_diagnostics_severity(new_severity, cx);
18151        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
18152            self.active_diagnostics = ActiveDiagnostic::None;
18153            self.inline_diagnostics_update = Task::ready(());
18154            self.inline_diagnostics.clear();
18155        } else {
18156            self.refresh_inline_diagnostics(false, window, cx);
18157        }
18158
18159        cx.notify();
18160    }
18161
18162    pub fn toggle_minimap(
18163        &mut self,
18164        _: &ToggleMinimap,
18165        window: &mut Window,
18166        cx: &mut Context<Editor>,
18167    ) {
18168        if self.supports_minimap(cx) {
18169            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
18170        }
18171    }
18172
18173    fn refresh_inline_diagnostics(
18174        &mut self,
18175        debounce: bool,
18176        window: &mut Window,
18177        cx: &mut Context<Self>,
18178    ) {
18179        let max_severity = ProjectSettings::get_global(cx)
18180            .diagnostics
18181            .inline
18182            .max_severity
18183            .unwrap_or(self.diagnostics_max_severity);
18184
18185        if !self.inline_diagnostics_enabled()
18186            || !self.diagnostics_enabled()
18187            || !self.show_inline_diagnostics
18188            || max_severity == DiagnosticSeverity::Off
18189        {
18190            self.inline_diagnostics_update = Task::ready(());
18191            self.inline_diagnostics.clear();
18192            return;
18193        }
18194
18195        let debounce_ms = ProjectSettings::get_global(cx)
18196            .diagnostics
18197            .inline
18198            .update_debounce_ms;
18199        let debounce = if debounce && debounce_ms > 0 {
18200            Some(Duration::from_millis(debounce_ms))
18201        } else {
18202            None
18203        };
18204        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
18205            if let Some(debounce) = debounce {
18206                cx.background_executor().timer(debounce).await;
18207            }
18208            let Some(snapshot) = editor.upgrade().and_then(|editor| {
18209                editor
18210                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
18211                    .ok()
18212            }) else {
18213                return;
18214            };
18215
18216            let new_inline_diagnostics = cx
18217                .background_spawn(async move {
18218                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
18219                    for diagnostic_entry in
18220                        snapshot.diagnostics_in_range(MultiBufferOffset(0)..snapshot.len())
18221                    {
18222                        let message = diagnostic_entry
18223                            .diagnostic
18224                            .message
18225                            .split_once('\n')
18226                            .map(|(line, _)| line)
18227                            .map(SharedString::new)
18228                            .unwrap_or_else(|| {
18229                                SharedString::new(&*diagnostic_entry.diagnostic.message)
18230                            });
18231                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
18232                        let (Ok(i) | Err(i)) = inline_diagnostics
18233                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
18234                        inline_diagnostics.insert(
18235                            i,
18236                            (
18237                                start_anchor,
18238                                InlineDiagnostic {
18239                                    message,
18240                                    group_id: diagnostic_entry.diagnostic.group_id,
18241                                    start: diagnostic_entry.range.start.to_point(&snapshot),
18242                                    is_primary: diagnostic_entry.diagnostic.is_primary,
18243                                    severity: diagnostic_entry.diagnostic.severity,
18244                                },
18245                            ),
18246                        );
18247                    }
18248                    inline_diagnostics
18249                })
18250                .await;
18251
18252            editor
18253                .update(cx, |editor, cx| {
18254                    editor.inline_diagnostics = new_inline_diagnostics;
18255                    cx.notify();
18256                })
18257                .ok();
18258        });
18259    }
18260
18261    fn pull_diagnostics(
18262        &mut self,
18263        buffer_id: Option<BufferId>,
18264        window: &Window,
18265        cx: &mut Context<Self>,
18266    ) -> Option<()> {
18267        if self.ignore_lsp_data() || !self.diagnostics_enabled() {
18268            return None;
18269        }
18270        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
18271            .diagnostics
18272            .lsp_pull_diagnostics;
18273        if !pull_diagnostics_settings.enabled {
18274            return None;
18275        }
18276        let project = self.project()?.downgrade();
18277        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
18278        let mut buffers = self.buffer.read(cx).all_buffers();
18279        buffers.retain(|buffer| {
18280            let buffer_id_to_retain = buffer.read(cx).remote_id();
18281            buffer_id.is_none_or(|buffer_id| buffer_id == buffer_id_to_retain)
18282                && self.registered_buffers.contains_key(&buffer_id_to_retain)
18283        });
18284        if buffers.is_empty() {
18285            self.pull_diagnostics_task = Task::ready(());
18286            return None;
18287        }
18288
18289        self.pull_diagnostics_task = cx.spawn_in(window, async move |editor, cx| {
18290            cx.background_executor().timer(debounce).await;
18291
18292            let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
18293                buffers
18294                    .into_iter()
18295                    .filter_map(|buffer| {
18296                        project
18297                            .update(cx, |project, cx| {
18298                                project.lsp_store().update(cx, |lsp_store, cx| {
18299                                    lsp_store.pull_diagnostics_for_buffer(buffer, cx)
18300                                })
18301                            })
18302                            .ok()
18303                    })
18304                    .collect::<FuturesUnordered<_>>()
18305            }) else {
18306                return;
18307            };
18308
18309            while let Some(pull_task) = pull_diagnostics_tasks.next().await {
18310                match pull_task {
18311                    Ok(()) => {
18312                        if editor
18313                            .update_in(cx, |editor, window, cx| {
18314                                editor.update_diagnostics_state(window, cx);
18315                            })
18316                            .is_err()
18317                        {
18318                            return;
18319                        }
18320                    }
18321                    Err(e) => log::error!("Failed to update project diagnostics: {e:#}"),
18322                }
18323            }
18324        });
18325
18326        Some(())
18327    }
18328
18329    pub fn set_selections_from_remote(
18330        &mut self,
18331        selections: Vec<Selection<Anchor>>,
18332        pending_selection: Option<Selection<Anchor>>,
18333        window: &mut Window,
18334        cx: &mut Context<Self>,
18335    ) {
18336        let old_cursor_position = self.selections.newest_anchor().head();
18337        self.selections
18338            .change_with(&self.display_snapshot(cx), |s| {
18339                s.select_anchors(selections);
18340                if let Some(pending_selection) = pending_selection {
18341                    s.set_pending(pending_selection, SelectMode::Character);
18342                } else {
18343                    s.clear_pending();
18344                }
18345            });
18346        self.selections_did_change(
18347            false,
18348            &old_cursor_position,
18349            SelectionEffects::default(),
18350            window,
18351            cx,
18352        );
18353    }
18354
18355    pub fn transact(
18356        &mut self,
18357        window: &mut Window,
18358        cx: &mut Context<Self>,
18359        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
18360    ) -> Option<TransactionId> {
18361        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
18362            this.start_transaction_at(Instant::now(), window, cx);
18363            update(this, window, cx);
18364            this.end_transaction_at(Instant::now(), cx)
18365        })
18366    }
18367
18368    pub fn start_transaction_at(
18369        &mut self,
18370        now: Instant,
18371        window: &mut Window,
18372        cx: &mut Context<Self>,
18373    ) -> Option<TransactionId> {
18374        self.end_selection(window, cx);
18375        if let Some(tx_id) = self
18376            .buffer
18377            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
18378        {
18379            self.selection_history
18380                .insert_transaction(tx_id, self.selections.disjoint_anchors_arc());
18381            cx.emit(EditorEvent::TransactionBegun {
18382                transaction_id: tx_id,
18383            });
18384            Some(tx_id)
18385        } else {
18386            None
18387        }
18388    }
18389
18390    pub fn end_transaction_at(
18391        &mut self,
18392        now: Instant,
18393        cx: &mut Context<Self>,
18394    ) -> Option<TransactionId> {
18395        if let Some(transaction_id) = self
18396            .buffer
18397            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
18398        {
18399            if let Some((_, end_selections)) =
18400                self.selection_history.transaction_mut(transaction_id)
18401            {
18402                *end_selections = Some(self.selections.disjoint_anchors_arc());
18403            } else {
18404                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
18405            }
18406
18407            cx.emit(EditorEvent::Edited { transaction_id });
18408            Some(transaction_id)
18409        } else {
18410            None
18411        }
18412    }
18413
18414    pub fn modify_transaction_selection_history(
18415        &mut self,
18416        transaction_id: TransactionId,
18417        modify: impl FnOnce(&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)),
18418    ) -> bool {
18419        self.selection_history
18420            .transaction_mut(transaction_id)
18421            .map(modify)
18422            .is_some()
18423    }
18424
18425    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
18426        if self.selection_mark_mode {
18427            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
18428                s.move_with(|_, sel| {
18429                    sel.collapse_to(sel.head(), SelectionGoal::None);
18430                });
18431            })
18432        }
18433        self.selection_mark_mode = true;
18434        cx.notify();
18435    }
18436
18437    pub fn swap_selection_ends(
18438        &mut self,
18439        _: &actions::SwapSelectionEnds,
18440        window: &mut Window,
18441        cx: &mut Context<Self>,
18442    ) {
18443        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
18444            s.move_with(|_, sel| {
18445                if sel.start != sel.end {
18446                    sel.reversed = !sel.reversed
18447                }
18448            });
18449        });
18450        self.request_autoscroll(Autoscroll::newest(), cx);
18451        cx.notify();
18452    }
18453
18454    pub fn toggle_focus(
18455        workspace: &mut Workspace,
18456        _: &actions::ToggleFocus,
18457        window: &mut Window,
18458        cx: &mut Context<Workspace>,
18459    ) {
18460        let Some(item) = workspace.recent_active_item_by_type::<Self>(cx) else {
18461            return;
18462        };
18463        workspace.activate_item(&item, true, true, window, cx);
18464    }
18465
18466    pub fn toggle_fold(
18467        &mut self,
18468        _: &actions::ToggleFold,
18469        window: &mut Window,
18470        cx: &mut Context<Self>,
18471    ) {
18472        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18473            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18474            let selection = self.selections.newest::<Point>(&display_map);
18475
18476            let range = if selection.is_empty() {
18477                let point = selection.head().to_display_point(&display_map);
18478                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
18479                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
18480                    .to_point(&display_map);
18481                start..end
18482            } else {
18483                selection.range()
18484            };
18485            if display_map.folds_in_range(range).next().is_some() {
18486                self.unfold_lines(&Default::default(), window, cx)
18487            } else {
18488                self.fold(&Default::default(), window, cx)
18489            }
18490        } else {
18491            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18492            let buffer_ids: HashSet<_> = self
18493                .selections
18494                .disjoint_anchor_ranges()
18495                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18496                .collect();
18497
18498            let should_unfold = buffer_ids
18499                .iter()
18500                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
18501
18502            for buffer_id in buffer_ids {
18503                if should_unfold {
18504                    self.unfold_buffer(buffer_id, cx);
18505                } else {
18506                    self.fold_buffer(buffer_id, cx);
18507                }
18508            }
18509        }
18510    }
18511
18512    pub fn toggle_fold_recursive(
18513        &mut self,
18514        _: &actions::ToggleFoldRecursive,
18515        window: &mut Window,
18516        cx: &mut Context<Self>,
18517    ) {
18518        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
18519
18520        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18521        let range = if selection.is_empty() {
18522            let point = selection.head().to_display_point(&display_map);
18523            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
18524            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
18525                .to_point(&display_map);
18526            start..end
18527        } else {
18528            selection.range()
18529        };
18530        if display_map.folds_in_range(range).next().is_some() {
18531            self.unfold_recursive(&Default::default(), window, cx)
18532        } else {
18533            self.fold_recursive(&Default::default(), window, cx)
18534        }
18535    }
18536
18537    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
18538        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18539            let mut to_fold = Vec::new();
18540            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18541            let selections = self.selections.all_adjusted(&display_map);
18542
18543            for selection in selections {
18544                let range = selection.range().sorted();
18545                let buffer_start_row = range.start.row;
18546
18547                if range.start.row != range.end.row {
18548                    let mut found = false;
18549                    let mut row = range.start.row;
18550                    while row <= range.end.row {
18551                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
18552                        {
18553                            found = true;
18554                            row = crease.range().end.row + 1;
18555                            to_fold.push(crease);
18556                        } else {
18557                            row += 1
18558                        }
18559                    }
18560                    if found {
18561                        continue;
18562                    }
18563                }
18564
18565                for row in (0..=range.start.row).rev() {
18566                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
18567                        && crease.range().end.row >= buffer_start_row
18568                    {
18569                        to_fold.push(crease);
18570                        if row <= range.start.row {
18571                            break;
18572                        }
18573                    }
18574                }
18575            }
18576
18577            self.fold_creases(to_fold, true, window, cx);
18578        } else {
18579            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18580            let buffer_ids = self
18581                .selections
18582                .disjoint_anchor_ranges()
18583                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18584                .collect::<HashSet<_>>();
18585            for buffer_id in buffer_ids {
18586                self.fold_buffer(buffer_id, cx);
18587            }
18588        }
18589    }
18590
18591    pub fn toggle_fold_all(
18592        &mut self,
18593        _: &actions::ToggleFoldAll,
18594        window: &mut Window,
18595        cx: &mut Context<Self>,
18596    ) {
18597        if self.buffer.read(cx).is_singleton() {
18598            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18599            let has_folds = display_map
18600                .folds_in_range(MultiBufferOffset(0)..display_map.buffer_snapshot().len())
18601                .next()
18602                .is_some();
18603
18604            if has_folds {
18605                self.unfold_all(&actions::UnfoldAll, window, cx);
18606            } else {
18607                self.fold_all(&actions::FoldAll, window, cx);
18608            }
18609        } else {
18610            let buffer_ids = self.buffer.read(cx).excerpt_buffer_ids();
18611            let should_unfold = buffer_ids
18612                .iter()
18613                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
18614
18615            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
18616                editor
18617                    .update_in(cx, |editor, _, cx| {
18618                        for buffer_id in buffer_ids {
18619                            if should_unfold {
18620                                editor.unfold_buffer(buffer_id, cx);
18621                            } else {
18622                                editor.fold_buffer(buffer_id, cx);
18623                            }
18624                        }
18625                    })
18626                    .ok();
18627            });
18628        }
18629    }
18630
18631    fn fold_at_level(
18632        &mut self,
18633        fold_at: &FoldAtLevel,
18634        window: &mut Window,
18635        cx: &mut Context<Self>,
18636    ) {
18637        if !self.buffer.read(cx).is_singleton() {
18638            return;
18639        }
18640
18641        let fold_at_level = fold_at.0;
18642        let snapshot = self.buffer.read(cx).snapshot(cx);
18643        let mut to_fold = Vec::new();
18644        let mut stack = vec![(0, snapshot.max_row().0, 1)];
18645
18646        let row_ranges_to_keep: Vec<Range<u32>> = self
18647            .selections
18648            .all::<Point>(&self.display_snapshot(cx))
18649            .into_iter()
18650            .map(|sel| sel.start.row..sel.end.row)
18651            .collect();
18652
18653        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
18654            while start_row < end_row {
18655                match self
18656                    .snapshot(window, cx)
18657                    .crease_for_buffer_row(MultiBufferRow(start_row))
18658                {
18659                    Some(crease) => {
18660                        let nested_start_row = crease.range().start.row + 1;
18661                        let nested_end_row = crease.range().end.row;
18662
18663                        if current_level < fold_at_level {
18664                            stack.push((nested_start_row, nested_end_row, current_level + 1));
18665                        } else if current_level == fold_at_level {
18666                            // Fold iff there is no selection completely contained within the fold region
18667                            if !row_ranges_to_keep.iter().any(|selection| {
18668                                selection.end >= nested_start_row
18669                                    && selection.start <= nested_end_row
18670                            }) {
18671                                to_fold.push(crease);
18672                            }
18673                        }
18674
18675                        start_row = nested_end_row + 1;
18676                    }
18677                    None => start_row += 1,
18678                }
18679            }
18680        }
18681
18682        self.fold_creases(to_fold, true, window, cx);
18683    }
18684
18685    pub fn fold_at_level_1(
18686        &mut self,
18687        _: &actions::FoldAtLevel1,
18688        window: &mut Window,
18689        cx: &mut Context<Self>,
18690    ) {
18691        self.fold_at_level(&actions::FoldAtLevel(1), window, cx);
18692    }
18693
18694    pub fn fold_at_level_2(
18695        &mut self,
18696        _: &actions::FoldAtLevel2,
18697        window: &mut Window,
18698        cx: &mut Context<Self>,
18699    ) {
18700        self.fold_at_level(&actions::FoldAtLevel(2), window, cx);
18701    }
18702
18703    pub fn fold_at_level_3(
18704        &mut self,
18705        _: &actions::FoldAtLevel3,
18706        window: &mut Window,
18707        cx: &mut Context<Self>,
18708    ) {
18709        self.fold_at_level(&actions::FoldAtLevel(3), window, cx);
18710    }
18711
18712    pub fn fold_at_level_4(
18713        &mut self,
18714        _: &actions::FoldAtLevel4,
18715        window: &mut Window,
18716        cx: &mut Context<Self>,
18717    ) {
18718        self.fold_at_level(&actions::FoldAtLevel(4), window, cx);
18719    }
18720
18721    pub fn fold_at_level_5(
18722        &mut self,
18723        _: &actions::FoldAtLevel5,
18724        window: &mut Window,
18725        cx: &mut Context<Self>,
18726    ) {
18727        self.fold_at_level(&actions::FoldAtLevel(5), window, cx);
18728    }
18729
18730    pub fn fold_at_level_6(
18731        &mut self,
18732        _: &actions::FoldAtLevel6,
18733        window: &mut Window,
18734        cx: &mut Context<Self>,
18735    ) {
18736        self.fold_at_level(&actions::FoldAtLevel(6), window, cx);
18737    }
18738
18739    pub fn fold_at_level_7(
18740        &mut self,
18741        _: &actions::FoldAtLevel7,
18742        window: &mut Window,
18743        cx: &mut Context<Self>,
18744    ) {
18745        self.fold_at_level(&actions::FoldAtLevel(7), window, cx);
18746    }
18747
18748    pub fn fold_at_level_8(
18749        &mut self,
18750        _: &actions::FoldAtLevel8,
18751        window: &mut Window,
18752        cx: &mut Context<Self>,
18753    ) {
18754        self.fold_at_level(&actions::FoldAtLevel(8), window, cx);
18755    }
18756
18757    pub fn fold_at_level_9(
18758        &mut self,
18759        _: &actions::FoldAtLevel9,
18760        window: &mut Window,
18761        cx: &mut Context<Self>,
18762    ) {
18763        self.fold_at_level(&actions::FoldAtLevel(9), window, cx);
18764    }
18765
18766    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
18767        if self.buffer.read(cx).is_singleton() {
18768            let mut fold_ranges = Vec::new();
18769            let snapshot = self.buffer.read(cx).snapshot(cx);
18770
18771            for row in 0..snapshot.max_row().0 {
18772                if let Some(foldable_range) = self
18773                    .snapshot(window, cx)
18774                    .crease_for_buffer_row(MultiBufferRow(row))
18775                {
18776                    fold_ranges.push(foldable_range);
18777                }
18778            }
18779
18780            self.fold_creases(fold_ranges, true, window, cx);
18781        } else {
18782            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
18783                editor
18784                    .update_in(cx, |editor, _, cx| {
18785                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
18786                            editor.fold_buffer(buffer_id, cx);
18787                        }
18788                    })
18789                    .ok();
18790            });
18791        }
18792    }
18793
18794    pub fn fold_function_bodies(
18795        &mut self,
18796        _: &actions::FoldFunctionBodies,
18797        window: &mut Window,
18798        cx: &mut Context<Self>,
18799    ) {
18800        let snapshot = self.buffer.read(cx).snapshot(cx);
18801
18802        let ranges = snapshot
18803            .text_object_ranges(
18804                MultiBufferOffset(0)..snapshot.len(),
18805                TreeSitterOptions::default(),
18806            )
18807            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
18808            .collect::<Vec<_>>();
18809
18810        let creases = ranges
18811            .into_iter()
18812            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
18813            .collect();
18814
18815        self.fold_creases(creases, true, window, cx);
18816    }
18817
18818    pub fn fold_recursive(
18819        &mut self,
18820        _: &actions::FoldRecursive,
18821        window: &mut Window,
18822        cx: &mut Context<Self>,
18823    ) {
18824        let mut to_fold = Vec::new();
18825        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18826        let selections = self.selections.all_adjusted(&display_map);
18827
18828        for selection in selections {
18829            let range = selection.range().sorted();
18830            let buffer_start_row = range.start.row;
18831
18832            if range.start.row != range.end.row {
18833                let mut found = false;
18834                for row in range.start.row..=range.end.row {
18835                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
18836                        found = true;
18837                        to_fold.push(crease);
18838                    }
18839                }
18840                if found {
18841                    continue;
18842                }
18843            }
18844
18845            for row in (0..=range.start.row).rev() {
18846                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
18847                    if crease.range().end.row >= buffer_start_row {
18848                        to_fold.push(crease);
18849                    } else {
18850                        break;
18851                    }
18852                }
18853            }
18854        }
18855
18856        self.fold_creases(to_fold, true, window, cx);
18857    }
18858
18859    pub fn fold_at(
18860        &mut self,
18861        buffer_row: MultiBufferRow,
18862        window: &mut Window,
18863        cx: &mut Context<Self>,
18864    ) {
18865        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18866
18867        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
18868            let autoscroll = self
18869                .selections
18870                .all::<Point>(&display_map)
18871                .iter()
18872                .any(|selection| crease.range().overlaps(&selection.range()));
18873
18874            self.fold_creases(vec![crease], autoscroll, window, cx);
18875        }
18876    }
18877
18878    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
18879        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18880            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18881            let buffer = display_map.buffer_snapshot();
18882            let selections = self.selections.all::<Point>(&display_map);
18883            let ranges = selections
18884                .iter()
18885                .map(|s| {
18886                    let range = s.display_range(&display_map).sorted();
18887                    let mut start = range.start.to_point(&display_map);
18888                    let mut end = range.end.to_point(&display_map);
18889                    start.column = 0;
18890                    end.column = buffer.line_len(MultiBufferRow(end.row));
18891                    start..end
18892                })
18893                .collect::<Vec<_>>();
18894
18895            self.unfold_ranges(&ranges, true, true, cx);
18896        } else {
18897            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18898            let buffer_ids = self
18899                .selections
18900                .disjoint_anchor_ranges()
18901                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18902                .collect::<HashSet<_>>();
18903            for buffer_id in buffer_ids {
18904                self.unfold_buffer(buffer_id, cx);
18905            }
18906        }
18907    }
18908
18909    pub fn unfold_recursive(
18910        &mut self,
18911        _: &UnfoldRecursive,
18912        _window: &mut Window,
18913        cx: &mut Context<Self>,
18914    ) {
18915        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18916        let selections = self.selections.all::<Point>(&display_map);
18917        let ranges = selections
18918            .iter()
18919            .map(|s| {
18920                let mut range = s.display_range(&display_map).sorted();
18921                *range.start.column_mut() = 0;
18922                *range.end.column_mut() = display_map.line_len(range.end.row());
18923                let start = range.start.to_point(&display_map);
18924                let end = range.end.to_point(&display_map);
18925                start..end
18926            })
18927            .collect::<Vec<_>>();
18928
18929        self.unfold_ranges(&ranges, true, true, cx);
18930    }
18931
18932    pub fn unfold_at(
18933        &mut self,
18934        buffer_row: MultiBufferRow,
18935        _window: &mut Window,
18936        cx: &mut Context<Self>,
18937    ) {
18938        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18939
18940        let intersection_range = Point::new(buffer_row.0, 0)
18941            ..Point::new(
18942                buffer_row.0,
18943                display_map.buffer_snapshot().line_len(buffer_row),
18944            );
18945
18946        let autoscroll = self
18947            .selections
18948            .all::<Point>(&display_map)
18949            .iter()
18950            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
18951
18952        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
18953    }
18954
18955    pub fn unfold_all(
18956        &mut self,
18957        _: &actions::UnfoldAll,
18958        _window: &mut Window,
18959        cx: &mut Context<Self>,
18960    ) {
18961        if self.buffer.read(cx).is_singleton() {
18962            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18963            self.unfold_ranges(
18964                &[MultiBufferOffset(0)..display_map.buffer_snapshot().len()],
18965                true,
18966                true,
18967                cx,
18968            );
18969        } else {
18970            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
18971                editor
18972                    .update(cx, |editor, cx| {
18973                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
18974                            editor.unfold_buffer(buffer_id, cx);
18975                        }
18976                    })
18977                    .ok();
18978            });
18979        }
18980    }
18981
18982    pub fn fold_selected_ranges(
18983        &mut self,
18984        _: &FoldSelectedRanges,
18985        window: &mut Window,
18986        cx: &mut Context<Self>,
18987    ) {
18988        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18989        let selections = self.selections.all_adjusted(&display_map);
18990        let ranges = selections
18991            .into_iter()
18992            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
18993            .collect::<Vec<_>>();
18994        self.fold_creases(ranges, true, window, cx);
18995    }
18996
18997    pub fn fold_ranges<T: ToOffset + Clone>(
18998        &mut self,
18999        ranges: Vec<Range<T>>,
19000        auto_scroll: bool,
19001        window: &mut Window,
19002        cx: &mut Context<Self>,
19003    ) {
19004        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19005        let ranges = ranges
19006            .into_iter()
19007            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
19008            .collect::<Vec<_>>();
19009        self.fold_creases(ranges, auto_scroll, window, cx);
19010    }
19011
19012    pub fn fold_creases<T: ToOffset + Clone>(
19013        &mut self,
19014        creases: Vec<Crease<T>>,
19015        auto_scroll: bool,
19016        _window: &mut Window,
19017        cx: &mut Context<Self>,
19018    ) {
19019        if creases.is_empty() {
19020            return;
19021        }
19022
19023        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
19024
19025        if auto_scroll {
19026            self.request_autoscroll(Autoscroll::fit(), cx);
19027        }
19028
19029        cx.notify();
19030
19031        self.scrollbar_marker_state.dirty = true;
19032        self.folds_did_change(cx);
19033    }
19034
19035    /// Removes any folds whose ranges intersect any of the given ranges.
19036    pub fn unfold_ranges<T: ToOffset + Clone>(
19037        &mut self,
19038        ranges: &[Range<T>],
19039        inclusive: bool,
19040        auto_scroll: bool,
19041        cx: &mut Context<Self>,
19042    ) {
19043        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
19044            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
19045        });
19046        self.folds_did_change(cx);
19047    }
19048
19049    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
19050        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
19051            return;
19052        }
19053
19054        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
19055        self.display_map.update(cx, |display_map, cx| {
19056            display_map.fold_buffers([buffer_id], cx)
19057        });
19058
19059        let snapshot = self.display_snapshot(cx);
19060        self.selections.change_with(&snapshot, |selections| {
19061            selections.remove_selections_from_buffer(buffer_id);
19062        });
19063
19064        cx.emit(EditorEvent::BufferFoldToggled {
19065            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
19066            folded: true,
19067        });
19068        cx.notify();
19069    }
19070
19071    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
19072        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
19073            return;
19074        }
19075        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
19076        self.display_map.update(cx, |display_map, cx| {
19077            display_map.unfold_buffers([buffer_id], cx);
19078        });
19079        cx.emit(EditorEvent::BufferFoldToggled {
19080            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
19081            folded: false,
19082        });
19083        cx.notify();
19084    }
19085
19086    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
19087        self.display_map.read(cx).is_buffer_folded(buffer)
19088    }
19089
19090    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
19091        self.display_map.read(cx).folded_buffers()
19092    }
19093
19094    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
19095        self.display_map.update(cx, |display_map, cx| {
19096            display_map.disable_header_for_buffer(buffer_id, cx);
19097        });
19098        cx.notify();
19099    }
19100
19101    /// Removes any folds with the given ranges.
19102    pub fn remove_folds_with_type<T: ToOffset + Clone>(
19103        &mut self,
19104        ranges: &[Range<T>],
19105        type_id: TypeId,
19106        auto_scroll: bool,
19107        cx: &mut Context<Self>,
19108    ) {
19109        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
19110            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
19111        });
19112        self.folds_did_change(cx);
19113    }
19114
19115    fn remove_folds_with<T: ToOffset + Clone>(
19116        &mut self,
19117        ranges: &[Range<T>],
19118        auto_scroll: bool,
19119        cx: &mut Context<Self>,
19120        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
19121    ) {
19122        if ranges.is_empty() {
19123            return;
19124        }
19125
19126        let mut buffers_affected = HashSet::default();
19127        let multi_buffer = self.buffer().read(cx);
19128        for range in ranges {
19129            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
19130                buffers_affected.insert(buffer.read(cx).remote_id());
19131            };
19132        }
19133
19134        self.display_map.update(cx, update);
19135
19136        if auto_scroll {
19137            self.request_autoscroll(Autoscroll::fit(), cx);
19138        }
19139
19140        cx.notify();
19141        self.scrollbar_marker_state.dirty = true;
19142        self.active_indent_guides_state.dirty = true;
19143    }
19144
19145    pub fn update_renderer_widths(
19146        &mut self,
19147        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
19148        cx: &mut Context<Self>,
19149    ) -> bool {
19150        self.display_map
19151            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
19152    }
19153
19154    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
19155        self.display_map.read(cx).fold_placeholder.clone()
19156    }
19157
19158    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
19159        self.buffer.update(cx, |buffer, cx| {
19160            buffer.set_all_diff_hunks_expanded(cx);
19161        });
19162    }
19163
19164    pub fn expand_all_diff_hunks(
19165        &mut self,
19166        _: &ExpandAllDiffHunks,
19167        _window: &mut Window,
19168        cx: &mut Context<Self>,
19169    ) {
19170        self.buffer.update(cx, |buffer, cx| {
19171            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
19172        });
19173    }
19174
19175    pub fn collapse_all_diff_hunks(
19176        &mut self,
19177        _: &CollapseAllDiffHunks,
19178        _window: &mut Window,
19179        cx: &mut Context<Self>,
19180    ) {
19181        self.buffer.update(cx, |buffer, cx| {
19182            buffer.collapse_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
19183        });
19184    }
19185
19186    pub fn toggle_selected_diff_hunks(
19187        &mut self,
19188        _: &ToggleSelectedDiffHunks,
19189        _window: &mut Window,
19190        cx: &mut Context<Self>,
19191    ) {
19192        let ranges: Vec<_> = self
19193            .selections
19194            .disjoint_anchors()
19195            .iter()
19196            .map(|s| s.range())
19197            .collect();
19198        self.toggle_diff_hunks_in_ranges(ranges, cx);
19199    }
19200
19201    pub fn diff_hunks_in_ranges<'a>(
19202        &'a self,
19203        ranges: &'a [Range<Anchor>],
19204        buffer: &'a MultiBufferSnapshot,
19205    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
19206        ranges.iter().flat_map(move |range| {
19207            let end_excerpt_id = range.end.excerpt_id;
19208            let range = range.to_point(buffer);
19209            let mut peek_end = range.end;
19210            if range.end.row < buffer.max_row().0 {
19211                peek_end = Point::new(range.end.row + 1, 0);
19212            }
19213            buffer
19214                .diff_hunks_in_range(range.start..peek_end)
19215                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
19216        })
19217    }
19218
19219    pub fn has_stageable_diff_hunks_in_ranges(
19220        &self,
19221        ranges: &[Range<Anchor>],
19222        snapshot: &MultiBufferSnapshot,
19223    ) -> bool {
19224        let mut hunks = self.diff_hunks_in_ranges(ranges, snapshot);
19225        hunks.any(|hunk| hunk.status().has_secondary_hunk())
19226    }
19227
19228    pub fn toggle_staged_selected_diff_hunks(
19229        &mut self,
19230        _: &::git::ToggleStaged,
19231        _: &mut Window,
19232        cx: &mut Context<Self>,
19233    ) {
19234        let snapshot = self.buffer.read(cx).snapshot(cx);
19235        let ranges: Vec<_> = self
19236            .selections
19237            .disjoint_anchors()
19238            .iter()
19239            .map(|s| s.range())
19240            .collect();
19241        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
19242        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
19243    }
19244
19245    pub fn set_render_diff_hunk_controls(
19246        &mut self,
19247        render_diff_hunk_controls: RenderDiffHunkControlsFn,
19248        cx: &mut Context<Self>,
19249    ) {
19250        self.render_diff_hunk_controls = render_diff_hunk_controls;
19251        cx.notify();
19252    }
19253
19254    pub fn stage_and_next(
19255        &mut self,
19256        _: &::git::StageAndNext,
19257        window: &mut Window,
19258        cx: &mut Context<Self>,
19259    ) {
19260        self.do_stage_or_unstage_and_next(true, window, cx);
19261    }
19262
19263    pub fn unstage_and_next(
19264        &mut self,
19265        _: &::git::UnstageAndNext,
19266        window: &mut Window,
19267        cx: &mut Context<Self>,
19268    ) {
19269        self.do_stage_or_unstage_and_next(false, window, cx);
19270    }
19271
19272    pub fn stage_or_unstage_diff_hunks(
19273        &mut self,
19274        stage: bool,
19275        ranges: Vec<Range<Anchor>>,
19276        cx: &mut Context<Self>,
19277    ) {
19278        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
19279        cx.spawn(async move |this, cx| {
19280            task.await?;
19281            this.update(cx, |this, cx| {
19282                let snapshot = this.buffer.read(cx).snapshot(cx);
19283                let chunk_by = this
19284                    .diff_hunks_in_ranges(&ranges, &snapshot)
19285                    .chunk_by(|hunk| hunk.buffer_id);
19286                for (buffer_id, hunks) in &chunk_by {
19287                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
19288                }
19289            })
19290        })
19291        .detach_and_log_err(cx);
19292    }
19293
19294    fn save_buffers_for_ranges_if_needed(
19295        &mut self,
19296        ranges: &[Range<Anchor>],
19297        cx: &mut Context<Editor>,
19298    ) -> Task<Result<()>> {
19299        let multibuffer = self.buffer.read(cx);
19300        let snapshot = multibuffer.read(cx);
19301        let buffer_ids: HashSet<_> = ranges
19302            .iter()
19303            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
19304            .collect();
19305        drop(snapshot);
19306
19307        let mut buffers = HashSet::default();
19308        for buffer_id in buffer_ids {
19309            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
19310                let buffer = buffer_entity.read(cx);
19311                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
19312                {
19313                    buffers.insert(buffer_entity);
19314                }
19315            }
19316        }
19317
19318        if let Some(project) = &self.project {
19319            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
19320        } else {
19321            Task::ready(Ok(()))
19322        }
19323    }
19324
19325    fn do_stage_or_unstage_and_next(
19326        &mut self,
19327        stage: bool,
19328        window: &mut Window,
19329        cx: &mut Context<Self>,
19330    ) {
19331        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
19332
19333        if ranges.iter().any(|range| range.start != range.end) {
19334            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
19335            return;
19336        }
19337
19338        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
19339        let snapshot = self.snapshot(window, cx);
19340        let position = self
19341            .selections
19342            .newest::<Point>(&snapshot.display_snapshot)
19343            .head();
19344        let mut row = snapshot
19345            .buffer_snapshot()
19346            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
19347            .find(|hunk| hunk.row_range.start.0 > position.row)
19348            .map(|hunk| hunk.row_range.start);
19349
19350        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
19351        // Outside of the project diff editor, wrap around to the beginning.
19352        if !all_diff_hunks_expanded {
19353            row = row.or_else(|| {
19354                snapshot
19355                    .buffer_snapshot()
19356                    .diff_hunks_in_range(Point::zero()..position)
19357                    .find(|hunk| hunk.row_range.end.0 < position.row)
19358                    .map(|hunk| hunk.row_range.start)
19359            });
19360        }
19361
19362        if let Some(row) = row {
19363            let destination = Point::new(row.0, 0);
19364            let autoscroll = Autoscroll::center();
19365
19366            self.unfold_ranges(&[destination..destination], false, false, cx);
19367            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
19368                s.select_ranges([destination..destination]);
19369            });
19370        }
19371    }
19372
19373    fn do_stage_or_unstage(
19374        &self,
19375        stage: bool,
19376        buffer_id: BufferId,
19377        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
19378        cx: &mut App,
19379    ) -> Option<()> {
19380        let project = self.project()?;
19381        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
19382        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
19383        let buffer_snapshot = buffer.read(cx).snapshot();
19384        let file_exists = buffer_snapshot
19385            .file()
19386            .is_some_and(|file| file.disk_state().exists());
19387        diff.update(cx, |diff, cx| {
19388            diff.stage_or_unstage_hunks(
19389                stage,
19390                &hunks
19391                    .map(|hunk| buffer_diff::DiffHunk {
19392                        buffer_range: hunk.buffer_range,
19393                        diff_base_byte_range: hunk.diff_base_byte_range.start.0
19394                            ..hunk.diff_base_byte_range.end.0,
19395                        secondary_status: hunk.secondary_status,
19396                        range: Point::zero()..Point::zero(), // unused
19397                    })
19398                    .collect::<Vec<_>>(),
19399                &buffer_snapshot,
19400                file_exists,
19401                cx,
19402            )
19403        });
19404        None
19405    }
19406
19407    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
19408        let ranges: Vec<_> = self
19409            .selections
19410            .disjoint_anchors()
19411            .iter()
19412            .map(|s| s.range())
19413            .collect();
19414        self.buffer
19415            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
19416    }
19417
19418    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
19419        self.buffer.update(cx, |buffer, cx| {
19420            let ranges = vec![Anchor::min()..Anchor::max()];
19421            if !buffer.all_diff_hunks_expanded()
19422                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
19423            {
19424                buffer.collapse_diff_hunks(ranges, cx);
19425                true
19426            } else {
19427                false
19428            }
19429        })
19430    }
19431
19432    fn has_any_expanded_diff_hunks(&self, cx: &App) -> bool {
19433        if self.buffer.read(cx).all_diff_hunks_expanded() {
19434            return true;
19435        }
19436        let ranges = vec![Anchor::min()..Anchor::max()];
19437        self.buffer
19438            .read(cx)
19439            .has_expanded_diff_hunks_in_ranges(&ranges, cx)
19440    }
19441
19442    fn toggle_diff_hunks_in_ranges(
19443        &mut self,
19444        ranges: Vec<Range<Anchor>>,
19445        cx: &mut Context<Editor>,
19446    ) {
19447        self.buffer.update(cx, |buffer, cx| {
19448            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
19449            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
19450        })
19451    }
19452
19453    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
19454        self.buffer.update(cx, |buffer, cx| {
19455            let snapshot = buffer.snapshot(cx);
19456            let excerpt_id = range.end.excerpt_id;
19457            let point_range = range.to_point(&snapshot);
19458            let expand = !buffer.single_hunk_is_expanded(range, cx);
19459            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
19460        })
19461    }
19462
19463    pub(crate) fn apply_all_diff_hunks(
19464        &mut self,
19465        _: &ApplyAllDiffHunks,
19466        window: &mut Window,
19467        cx: &mut Context<Self>,
19468    ) {
19469        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19470
19471        let buffers = self.buffer.read(cx).all_buffers();
19472        for branch_buffer in buffers {
19473            branch_buffer.update(cx, |branch_buffer, cx| {
19474                branch_buffer.merge_into_base(Vec::new(), cx);
19475            });
19476        }
19477
19478        if let Some(project) = self.project.clone() {
19479            self.save(
19480                SaveOptions {
19481                    format: true,
19482                    autosave: false,
19483                },
19484                project,
19485                window,
19486                cx,
19487            )
19488            .detach_and_log_err(cx);
19489        }
19490    }
19491
19492    pub(crate) fn apply_selected_diff_hunks(
19493        &mut self,
19494        _: &ApplyDiffHunk,
19495        window: &mut Window,
19496        cx: &mut Context<Self>,
19497    ) {
19498        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19499        let snapshot = self.snapshot(window, cx);
19500        let hunks = snapshot.hunks_for_ranges(
19501            self.selections
19502                .all(&snapshot.display_snapshot)
19503                .into_iter()
19504                .map(|selection| selection.range()),
19505        );
19506        let mut ranges_by_buffer = HashMap::default();
19507        self.transact(window, cx, |editor, _window, cx| {
19508            for hunk in hunks {
19509                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
19510                    ranges_by_buffer
19511                        .entry(buffer.clone())
19512                        .or_insert_with(Vec::new)
19513                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
19514                }
19515            }
19516
19517            for (buffer, ranges) in ranges_by_buffer {
19518                buffer.update(cx, |buffer, cx| {
19519                    buffer.merge_into_base(ranges, cx);
19520                });
19521            }
19522        });
19523
19524        if let Some(project) = self.project.clone() {
19525            self.save(
19526                SaveOptions {
19527                    format: true,
19528                    autosave: false,
19529                },
19530                project,
19531                window,
19532                cx,
19533            )
19534            .detach_and_log_err(cx);
19535        }
19536    }
19537
19538    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
19539        if hovered != self.gutter_hovered {
19540            self.gutter_hovered = hovered;
19541            cx.notify();
19542        }
19543    }
19544
19545    pub fn insert_blocks(
19546        &mut self,
19547        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
19548        autoscroll: Option<Autoscroll>,
19549        cx: &mut Context<Self>,
19550    ) -> Vec<CustomBlockId> {
19551        let blocks = self
19552            .display_map
19553            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
19554        if let Some(autoscroll) = autoscroll {
19555            self.request_autoscroll(autoscroll, cx);
19556        }
19557        cx.notify();
19558        blocks
19559    }
19560
19561    pub fn resize_blocks(
19562        &mut self,
19563        heights: HashMap<CustomBlockId, u32>,
19564        autoscroll: Option<Autoscroll>,
19565        cx: &mut Context<Self>,
19566    ) {
19567        self.display_map
19568            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
19569        if let Some(autoscroll) = autoscroll {
19570            self.request_autoscroll(autoscroll, cx);
19571        }
19572        cx.notify();
19573    }
19574
19575    pub fn replace_blocks(
19576        &mut self,
19577        renderers: HashMap<CustomBlockId, RenderBlock>,
19578        autoscroll: Option<Autoscroll>,
19579        cx: &mut Context<Self>,
19580    ) {
19581        self.display_map
19582            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
19583        if let Some(autoscroll) = autoscroll {
19584            self.request_autoscroll(autoscroll, cx);
19585        }
19586        cx.notify();
19587    }
19588
19589    pub fn remove_blocks(
19590        &mut self,
19591        block_ids: HashSet<CustomBlockId>,
19592        autoscroll: Option<Autoscroll>,
19593        cx: &mut Context<Self>,
19594    ) {
19595        self.display_map.update(cx, |display_map, cx| {
19596            display_map.remove_blocks(block_ids, cx)
19597        });
19598        if let Some(autoscroll) = autoscroll {
19599            self.request_autoscroll(autoscroll, cx);
19600        }
19601        cx.notify();
19602    }
19603
19604    pub fn row_for_block(
19605        &self,
19606        block_id: CustomBlockId,
19607        cx: &mut Context<Self>,
19608    ) -> Option<DisplayRow> {
19609        self.display_map
19610            .update(cx, |map, cx| map.row_for_block(block_id, cx))
19611    }
19612
19613    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
19614        self.focused_block = Some(focused_block);
19615    }
19616
19617    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
19618        self.focused_block.take()
19619    }
19620
19621    pub fn insert_creases(
19622        &mut self,
19623        creases: impl IntoIterator<Item = Crease<Anchor>>,
19624        cx: &mut Context<Self>,
19625    ) -> Vec<CreaseId> {
19626        self.display_map
19627            .update(cx, |map, cx| map.insert_creases(creases, cx))
19628    }
19629
19630    pub fn remove_creases(
19631        &mut self,
19632        ids: impl IntoIterator<Item = CreaseId>,
19633        cx: &mut Context<Self>,
19634    ) -> Vec<(CreaseId, Range<Anchor>)> {
19635        self.display_map
19636            .update(cx, |map, cx| map.remove_creases(ids, cx))
19637    }
19638
19639    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
19640        self.display_map
19641            .update(cx, |map, cx| map.snapshot(cx))
19642            .longest_row()
19643    }
19644
19645    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
19646        self.display_map
19647            .update(cx, |map, cx| map.snapshot(cx))
19648            .max_point()
19649    }
19650
19651    pub fn text(&self, cx: &App) -> String {
19652        self.buffer.read(cx).read(cx).text()
19653    }
19654
19655    pub fn is_empty(&self, cx: &App) -> bool {
19656        self.buffer.read(cx).read(cx).is_empty()
19657    }
19658
19659    pub fn text_option(&self, cx: &App) -> Option<String> {
19660        let text = self.text(cx);
19661        let text = text.trim();
19662
19663        if text.is_empty() {
19664            return None;
19665        }
19666
19667        Some(text.to_string())
19668    }
19669
19670    pub fn set_text(
19671        &mut self,
19672        text: impl Into<Arc<str>>,
19673        window: &mut Window,
19674        cx: &mut Context<Self>,
19675    ) {
19676        self.transact(window, cx, |this, _, cx| {
19677            this.buffer
19678                .read(cx)
19679                .as_singleton()
19680                .expect("you can only call set_text on editors for singleton buffers")
19681                .update(cx, |buffer, cx| buffer.set_text(text, cx));
19682        });
19683    }
19684
19685    pub fn display_text(&self, cx: &mut App) -> String {
19686        self.display_map
19687            .update(cx, |map, cx| map.snapshot(cx))
19688            .text()
19689    }
19690
19691    fn create_minimap(
19692        &self,
19693        minimap_settings: MinimapSettings,
19694        window: &mut Window,
19695        cx: &mut Context<Self>,
19696    ) -> Option<Entity<Self>> {
19697        (minimap_settings.minimap_enabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton)
19698            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
19699    }
19700
19701    fn initialize_new_minimap(
19702        &self,
19703        minimap_settings: MinimapSettings,
19704        window: &mut Window,
19705        cx: &mut Context<Self>,
19706    ) -> Entity<Self> {
19707        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
19708
19709        let mut minimap = Editor::new_internal(
19710            EditorMode::Minimap {
19711                parent: cx.weak_entity(),
19712            },
19713            self.buffer.clone(),
19714            None,
19715            Some(self.display_map.clone()),
19716            window,
19717            cx,
19718        );
19719        minimap.scroll_manager.clone_state(&self.scroll_manager);
19720        minimap.set_text_style_refinement(TextStyleRefinement {
19721            font_size: Some(MINIMAP_FONT_SIZE),
19722            font_weight: Some(MINIMAP_FONT_WEIGHT),
19723            ..Default::default()
19724        });
19725        minimap.update_minimap_configuration(minimap_settings, cx);
19726        cx.new(|_| minimap)
19727    }
19728
19729    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
19730        let current_line_highlight = minimap_settings
19731            .current_line_highlight
19732            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
19733        self.set_current_line_highlight(Some(current_line_highlight));
19734    }
19735
19736    pub fn minimap(&self) -> Option<&Entity<Self>> {
19737        self.minimap
19738            .as_ref()
19739            .filter(|_| self.minimap_visibility.visible())
19740    }
19741
19742    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
19743        let mut wrap_guides = smallvec![];
19744
19745        if self.show_wrap_guides == Some(false) {
19746            return wrap_guides;
19747        }
19748
19749        let settings = self.buffer.read(cx).language_settings(cx);
19750        if settings.show_wrap_guides {
19751            match self.soft_wrap_mode(cx) {
19752                SoftWrap::Column(soft_wrap) => {
19753                    wrap_guides.push((soft_wrap as usize, true));
19754                }
19755                SoftWrap::Bounded(soft_wrap) => {
19756                    wrap_guides.push((soft_wrap as usize, true));
19757                }
19758                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
19759            }
19760            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
19761        }
19762
19763        wrap_guides
19764    }
19765
19766    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
19767        let settings = self.buffer.read(cx).language_settings(cx);
19768        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
19769        match mode {
19770            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
19771                SoftWrap::None
19772            }
19773            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
19774            language_settings::SoftWrap::PreferredLineLength => {
19775                SoftWrap::Column(settings.preferred_line_length)
19776            }
19777            language_settings::SoftWrap::Bounded => {
19778                SoftWrap::Bounded(settings.preferred_line_length)
19779            }
19780        }
19781    }
19782
19783    pub fn set_soft_wrap_mode(
19784        &mut self,
19785        mode: language_settings::SoftWrap,
19786
19787        cx: &mut Context<Self>,
19788    ) {
19789        self.soft_wrap_mode_override = Some(mode);
19790        cx.notify();
19791    }
19792
19793    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
19794        self.hard_wrap = hard_wrap;
19795        cx.notify();
19796    }
19797
19798    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
19799        self.text_style_refinement = Some(style);
19800    }
19801
19802    /// called by the Element so we know what style we were most recently rendered with.
19803    pub fn set_style(&mut self, style: EditorStyle, window: &mut Window, cx: &mut Context<Self>) {
19804        // We intentionally do not inform the display map about the minimap style
19805        // so that wrapping is not recalculated and stays consistent for the editor
19806        // and its linked minimap.
19807        if !self.mode.is_minimap() {
19808            let font = style.text.font();
19809            let font_size = style.text.font_size.to_pixels(window.rem_size());
19810            let display_map = self
19811                .placeholder_display_map
19812                .as_ref()
19813                .filter(|_| self.is_empty(cx))
19814                .unwrap_or(&self.display_map);
19815
19816            display_map.update(cx, |map, cx| map.set_font(font, font_size, cx));
19817        }
19818        self.style = Some(style);
19819    }
19820
19821    pub fn style(&self) -> Option<&EditorStyle> {
19822        self.style.as_ref()
19823    }
19824
19825    // Called by the element. This method is not designed to be called outside of the editor
19826    // element's layout code because it does not notify when rewrapping is computed synchronously.
19827    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
19828        if self.is_empty(cx) {
19829            self.placeholder_display_map
19830                .as_ref()
19831                .map_or(false, |display_map| {
19832                    display_map.update(cx, |map, cx| map.set_wrap_width(width, cx))
19833                })
19834        } else {
19835            self.display_map
19836                .update(cx, |map, cx| map.set_wrap_width(width, cx))
19837        }
19838    }
19839
19840    pub fn set_soft_wrap(&mut self) {
19841        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
19842    }
19843
19844    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
19845        if self.soft_wrap_mode_override.is_some() {
19846            self.soft_wrap_mode_override.take();
19847        } else {
19848            let soft_wrap = match self.soft_wrap_mode(cx) {
19849                SoftWrap::GitDiff => return,
19850                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
19851                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
19852                    language_settings::SoftWrap::None
19853                }
19854            };
19855            self.soft_wrap_mode_override = Some(soft_wrap);
19856        }
19857        cx.notify();
19858    }
19859
19860    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
19861        let Some(workspace) = self.workspace() else {
19862            return;
19863        };
19864        let fs = workspace.read(cx).app_state().fs.clone();
19865        let current_show = TabBarSettings::get_global(cx).show;
19866        update_settings_file(fs, cx, move |setting, _| {
19867            setting.tab_bar.get_or_insert_default().show = Some(!current_show);
19868        });
19869    }
19870
19871    pub fn toggle_indent_guides(
19872        &mut self,
19873        _: &ToggleIndentGuides,
19874        _: &mut Window,
19875        cx: &mut Context<Self>,
19876    ) {
19877        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
19878            self.buffer
19879                .read(cx)
19880                .language_settings(cx)
19881                .indent_guides
19882                .enabled
19883        });
19884        self.show_indent_guides = Some(!currently_enabled);
19885        cx.notify();
19886    }
19887
19888    fn should_show_indent_guides(&self) -> Option<bool> {
19889        self.show_indent_guides
19890    }
19891
19892    pub fn toggle_line_numbers(
19893        &mut self,
19894        _: &ToggleLineNumbers,
19895        _: &mut Window,
19896        cx: &mut Context<Self>,
19897    ) {
19898        let mut editor_settings = EditorSettings::get_global(cx).clone();
19899        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
19900        EditorSettings::override_global(editor_settings, cx);
19901    }
19902
19903    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
19904        if let Some(show_line_numbers) = self.show_line_numbers {
19905            return show_line_numbers;
19906        }
19907        EditorSettings::get_global(cx).gutter.line_numbers
19908    }
19909
19910    pub fn relative_line_numbers(&self, cx: &mut App) -> RelativeLineNumbers {
19911        match (
19912            self.use_relative_line_numbers,
19913            EditorSettings::get_global(cx).relative_line_numbers,
19914        ) {
19915            (None, setting) => setting,
19916            (Some(false), _) => RelativeLineNumbers::Disabled,
19917            (Some(true), RelativeLineNumbers::Wrapped) => RelativeLineNumbers::Wrapped,
19918            (Some(true), _) => RelativeLineNumbers::Enabled,
19919        }
19920    }
19921
19922    pub fn toggle_relative_line_numbers(
19923        &mut self,
19924        _: &ToggleRelativeLineNumbers,
19925        _: &mut Window,
19926        cx: &mut Context<Self>,
19927    ) {
19928        let is_relative = self.relative_line_numbers(cx);
19929        self.set_relative_line_number(Some(!is_relative.enabled()), cx)
19930    }
19931
19932    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
19933        self.use_relative_line_numbers = is_relative;
19934        cx.notify();
19935    }
19936
19937    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
19938        self.show_gutter = show_gutter;
19939        cx.notify();
19940    }
19941
19942    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
19943        self.show_scrollbars = ScrollbarAxes {
19944            horizontal: show,
19945            vertical: show,
19946        };
19947        cx.notify();
19948    }
19949
19950    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
19951        self.show_scrollbars.vertical = show;
19952        cx.notify();
19953    }
19954
19955    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
19956        self.show_scrollbars.horizontal = show;
19957        cx.notify();
19958    }
19959
19960    pub fn set_minimap_visibility(
19961        &mut self,
19962        minimap_visibility: MinimapVisibility,
19963        window: &mut Window,
19964        cx: &mut Context<Self>,
19965    ) {
19966        if self.minimap_visibility != minimap_visibility {
19967            if minimap_visibility.visible() && self.minimap.is_none() {
19968                let minimap_settings = EditorSettings::get_global(cx).minimap;
19969                self.minimap =
19970                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
19971            }
19972            self.minimap_visibility = minimap_visibility;
19973            cx.notify();
19974        }
19975    }
19976
19977    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19978        self.set_show_scrollbars(false, cx);
19979        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
19980    }
19981
19982    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19983        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
19984    }
19985
19986    /// Normally the text in full mode and auto height editors is padded on the
19987    /// left side by roughly half a character width for improved hit testing.
19988    ///
19989    /// Use this method to disable this for cases where this is not wanted (e.g.
19990    /// if you want to align the editor text with some other text above or below)
19991    /// or if you want to add this padding to single-line editors.
19992    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
19993        self.offset_content = offset_content;
19994        cx.notify();
19995    }
19996
19997    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
19998        self.show_line_numbers = Some(show_line_numbers);
19999        cx.notify();
20000    }
20001
20002    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
20003        self.disable_expand_excerpt_buttons = true;
20004        cx.notify();
20005    }
20006
20007    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
20008        self.show_git_diff_gutter = Some(show_git_diff_gutter);
20009        cx.notify();
20010    }
20011
20012    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
20013        self.show_code_actions = Some(show_code_actions);
20014        cx.notify();
20015    }
20016
20017    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
20018        self.show_runnables = Some(show_runnables);
20019        cx.notify();
20020    }
20021
20022    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
20023        self.show_breakpoints = Some(show_breakpoints);
20024        cx.notify();
20025    }
20026
20027    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
20028        if self.display_map.read(cx).masked != masked {
20029            self.display_map.update(cx, |map, _| map.masked = masked);
20030        }
20031        cx.notify()
20032    }
20033
20034    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
20035        self.show_wrap_guides = Some(show_wrap_guides);
20036        cx.notify();
20037    }
20038
20039    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
20040        self.show_indent_guides = Some(show_indent_guides);
20041        cx.notify();
20042    }
20043
20044    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
20045        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
20046            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local())
20047                && let Some(dir) = file.abs_path(cx).parent()
20048            {
20049                return Some(dir.to_owned());
20050            }
20051        }
20052
20053        None
20054    }
20055
20056    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
20057        self.active_excerpt(cx)?
20058            .1
20059            .read(cx)
20060            .file()
20061            .and_then(|f| f.as_local())
20062    }
20063
20064    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
20065        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
20066            let buffer = buffer.read(cx);
20067            if let Some(project_path) = buffer.project_path(cx) {
20068                let project = self.project()?.read(cx);
20069                project.absolute_path(&project_path, cx)
20070            } else {
20071                buffer
20072                    .file()
20073                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
20074            }
20075        })
20076    }
20077
20078    pub fn reveal_in_finder(
20079        &mut self,
20080        _: &RevealInFileManager,
20081        _window: &mut Window,
20082        cx: &mut Context<Self>,
20083    ) {
20084        if let Some(target) = self.target_file(cx) {
20085            cx.reveal_path(&target.abs_path(cx));
20086        }
20087    }
20088
20089    pub fn copy_path(
20090        &mut self,
20091        _: &zed_actions::workspace::CopyPath,
20092        _window: &mut Window,
20093        cx: &mut Context<Self>,
20094    ) {
20095        if let Some(path) = self.target_file_abs_path(cx)
20096            && let Some(path) = path.to_str()
20097        {
20098            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
20099        } else {
20100            cx.propagate();
20101        }
20102    }
20103
20104    pub fn copy_relative_path(
20105        &mut self,
20106        _: &zed_actions::workspace::CopyRelativePath,
20107        _window: &mut Window,
20108        cx: &mut Context<Self>,
20109    ) {
20110        if let Some(path) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
20111            let project = self.project()?.read(cx);
20112            let path = buffer.read(cx).file()?.path();
20113            let path = path.display(project.path_style(cx));
20114            Some(path)
20115        }) {
20116            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
20117        } else {
20118            cx.propagate();
20119        }
20120    }
20121
20122    /// Returns the project path for the editor's buffer, if any buffer is
20123    /// opened in the editor.
20124    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
20125        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
20126            buffer.read(cx).project_path(cx)
20127        } else {
20128            None
20129        }
20130    }
20131
20132    // Returns true if the editor handled a go-to-line request
20133    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
20134        maybe!({
20135            let breakpoint_store = self.breakpoint_store.as_ref()?;
20136
20137            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
20138            else {
20139                self.clear_row_highlights::<ActiveDebugLine>();
20140                return None;
20141            };
20142
20143            let position = active_stack_frame.position;
20144            let buffer_id = position.buffer_id?;
20145            let snapshot = self
20146                .project
20147                .as_ref()?
20148                .read(cx)
20149                .buffer_for_id(buffer_id, cx)?
20150                .read(cx)
20151                .snapshot();
20152
20153            let mut handled = false;
20154            for (id, ExcerptRange { context, .. }) in
20155                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
20156            {
20157                if context.start.cmp(&position, &snapshot).is_ge()
20158                    || context.end.cmp(&position, &snapshot).is_lt()
20159                {
20160                    continue;
20161                }
20162                let snapshot = self.buffer.read(cx).snapshot(cx);
20163                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
20164
20165                handled = true;
20166                self.clear_row_highlights::<ActiveDebugLine>();
20167
20168                self.go_to_line::<ActiveDebugLine>(
20169                    multibuffer_anchor,
20170                    Some(cx.theme().colors().editor_debugger_active_line_background),
20171                    window,
20172                    cx,
20173                );
20174
20175                cx.notify();
20176            }
20177
20178            handled.then_some(())
20179        })
20180        .is_some()
20181    }
20182
20183    pub fn copy_file_name_without_extension(
20184        &mut self,
20185        _: &CopyFileNameWithoutExtension,
20186        _: &mut Window,
20187        cx: &mut Context<Self>,
20188    ) {
20189        if let Some(file) = self.target_file(cx)
20190            && let Some(file_stem) = file.path().file_stem()
20191        {
20192            cx.write_to_clipboard(ClipboardItem::new_string(file_stem.to_string()));
20193        }
20194    }
20195
20196    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
20197        if let Some(file) = self.target_file(cx)
20198            && let Some(name) = file.path().file_name()
20199        {
20200            cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
20201        }
20202    }
20203
20204    pub fn toggle_git_blame(
20205        &mut self,
20206        _: &::git::Blame,
20207        window: &mut Window,
20208        cx: &mut Context<Self>,
20209    ) {
20210        self.show_git_blame_gutter = !self.show_git_blame_gutter;
20211
20212        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
20213            self.start_git_blame(true, window, cx);
20214        }
20215
20216        cx.notify();
20217    }
20218
20219    pub fn toggle_git_blame_inline(
20220        &mut self,
20221        _: &ToggleGitBlameInline,
20222        window: &mut Window,
20223        cx: &mut Context<Self>,
20224    ) {
20225        self.toggle_git_blame_inline_internal(true, window, cx);
20226        cx.notify();
20227    }
20228
20229    pub fn open_git_blame_commit(
20230        &mut self,
20231        _: &OpenGitBlameCommit,
20232        window: &mut Window,
20233        cx: &mut Context<Self>,
20234    ) {
20235        self.open_git_blame_commit_internal(window, cx);
20236    }
20237
20238    fn open_git_blame_commit_internal(
20239        &mut self,
20240        window: &mut Window,
20241        cx: &mut Context<Self>,
20242    ) -> Option<()> {
20243        let blame = self.blame.as_ref()?;
20244        let snapshot = self.snapshot(window, cx);
20245        let cursor = self
20246            .selections
20247            .newest::<Point>(&snapshot.display_snapshot)
20248            .head();
20249        let (buffer, point, _) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)?;
20250        let (_, blame_entry) = blame
20251            .update(cx, |blame, cx| {
20252                blame
20253                    .blame_for_rows(
20254                        &[RowInfo {
20255                            buffer_id: Some(buffer.remote_id()),
20256                            buffer_row: Some(point.row),
20257                            ..Default::default()
20258                        }],
20259                        cx,
20260                    )
20261                    .next()
20262            })
20263            .flatten()?;
20264        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
20265        let repo = blame.read(cx).repository(cx, buffer.remote_id())?;
20266        let workspace = self.workspace()?.downgrade();
20267        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
20268        None
20269    }
20270
20271    pub fn git_blame_inline_enabled(&self) -> bool {
20272        self.git_blame_inline_enabled
20273    }
20274
20275    pub fn toggle_selection_menu(
20276        &mut self,
20277        _: &ToggleSelectionMenu,
20278        _: &mut Window,
20279        cx: &mut Context<Self>,
20280    ) {
20281        self.show_selection_menu = self
20282            .show_selection_menu
20283            .map(|show_selections_menu| !show_selections_menu)
20284            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
20285
20286        cx.notify();
20287    }
20288
20289    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
20290        self.show_selection_menu
20291            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
20292    }
20293
20294    fn start_git_blame(
20295        &mut self,
20296        user_triggered: bool,
20297        window: &mut Window,
20298        cx: &mut Context<Self>,
20299    ) {
20300        if let Some(project) = self.project() {
20301            if let Some(buffer) = self.buffer().read(cx).as_singleton()
20302                && buffer.read(cx).file().is_none()
20303            {
20304                return;
20305            }
20306
20307            let focused = self.focus_handle(cx).contains_focused(window, cx);
20308
20309            let project = project.clone();
20310            let blame = cx
20311                .new(|cx| GitBlame::new(self.buffer.clone(), project, user_triggered, focused, cx));
20312            self.blame_subscription =
20313                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
20314            self.blame = Some(blame);
20315        }
20316    }
20317
20318    fn toggle_git_blame_inline_internal(
20319        &mut self,
20320        user_triggered: bool,
20321        window: &mut Window,
20322        cx: &mut Context<Self>,
20323    ) {
20324        if self.git_blame_inline_enabled {
20325            self.git_blame_inline_enabled = false;
20326            self.show_git_blame_inline = false;
20327            self.show_git_blame_inline_delay_task.take();
20328        } else {
20329            self.git_blame_inline_enabled = true;
20330            self.start_git_blame_inline(user_triggered, window, cx);
20331        }
20332
20333        cx.notify();
20334    }
20335
20336    fn start_git_blame_inline(
20337        &mut self,
20338        user_triggered: bool,
20339        window: &mut Window,
20340        cx: &mut Context<Self>,
20341    ) {
20342        self.start_git_blame(user_triggered, window, cx);
20343
20344        if ProjectSettings::get_global(cx)
20345            .git
20346            .inline_blame_delay()
20347            .is_some()
20348        {
20349            self.start_inline_blame_timer(window, cx);
20350        } else {
20351            self.show_git_blame_inline = true
20352        }
20353    }
20354
20355    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
20356        self.blame.as_ref()
20357    }
20358
20359    pub fn show_git_blame_gutter(&self) -> bool {
20360        self.show_git_blame_gutter
20361    }
20362
20363    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
20364        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
20365    }
20366
20367    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
20368        self.show_git_blame_inline
20369            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
20370            && !self.newest_selection_head_on_empty_line(cx)
20371            && self.has_blame_entries(cx)
20372    }
20373
20374    fn has_blame_entries(&self, cx: &App) -> bool {
20375        self.blame()
20376            .is_some_and(|blame| blame.read(cx).has_generated_entries())
20377    }
20378
20379    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
20380        let cursor_anchor = self.selections.newest_anchor().head();
20381
20382        let snapshot = self.buffer.read(cx).snapshot(cx);
20383        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
20384
20385        snapshot.line_len(buffer_row) == 0
20386    }
20387
20388    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
20389        let buffer_and_selection = maybe!({
20390            let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
20391            let selection_range = selection.range();
20392
20393            let multi_buffer = self.buffer().read(cx);
20394            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
20395            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
20396
20397            let (buffer, range, _) = if selection.reversed {
20398                buffer_ranges.first()
20399            } else {
20400                buffer_ranges.last()
20401            }?;
20402
20403            let selection = text::ToPoint::to_point(&range.start, buffer).row
20404                ..text::ToPoint::to_point(&range.end, buffer).row;
20405            Some((multi_buffer.buffer(buffer.remote_id()).unwrap(), selection))
20406        });
20407
20408        let Some((buffer, selection)) = buffer_and_selection else {
20409            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
20410        };
20411
20412        let Some(project) = self.project() else {
20413            return Task::ready(Err(anyhow!("editor does not have project")));
20414        };
20415
20416        project.update(cx, |project, cx| {
20417            project.get_permalink_to_line(&buffer, selection, cx)
20418        })
20419    }
20420
20421    pub fn copy_permalink_to_line(
20422        &mut self,
20423        _: &CopyPermalinkToLine,
20424        window: &mut Window,
20425        cx: &mut Context<Self>,
20426    ) {
20427        let permalink_task = self.get_permalink_to_line(cx);
20428        let workspace = self.workspace();
20429
20430        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
20431            Ok(permalink) => {
20432                cx.update(|_, cx| {
20433                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
20434                })
20435                .ok();
20436            }
20437            Err(err) => {
20438                let message = format!("Failed to copy permalink: {err}");
20439
20440                anyhow::Result::<()>::Err(err).log_err();
20441
20442                if let Some(workspace) = workspace {
20443                    workspace
20444                        .update_in(cx, |workspace, _, cx| {
20445                            struct CopyPermalinkToLine;
20446
20447                            workspace.show_toast(
20448                                Toast::new(
20449                                    NotificationId::unique::<CopyPermalinkToLine>(),
20450                                    message,
20451                                ),
20452                                cx,
20453                            )
20454                        })
20455                        .ok();
20456                }
20457            }
20458        })
20459        .detach();
20460    }
20461
20462    pub fn copy_file_location(
20463        &mut self,
20464        _: &CopyFileLocation,
20465        _: &mut Window,
20466        cx: &mut Context<Self>,
20467    ) {
20468        let selection = self
20469            .selections
20470            .newest::<Point>(&self.display_snapshot(cx))
20471            .start
20472            .row
20473            + 1;
20474        if let Some(file) = self.target_file(cx) {
20475            let path = file.path().display(file.path_style(cx));
20476            cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
20477        }
20478    }
20479
20480    pub fn open_permalink_to_line(
20481        &mut self,
20482        _: &OpenPermalinkToLine,
20483        window: &mut Window,
20484        cx: &mut Context<Self>,
20485    ) {
20486        let permalink_task = self.get_permalink_to_line(cx);
20487        let workspace = self.workspace();
20488
20489        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
20490            Ok(permalink) => {
20491                cx.update(|_, cx| {
20492                    cx.open_url(permalink.as_ref());
20493                })
20494                .ok();
20495            }
20496            Err(err) => {
20497                let message = format!("Failed to open permalink: {err}");
20498
20499                anyhow::Result::<()>::Err(err).log_err();
20500
20501                if let Some(workspace) = workspace {
20502                    workspace
20503                        .update(cx, |workspace, cx| {
20504                            struct OpenPermalinkToLine;
20505
20506                            workspace.show_toast(
20507                                Toast::new(
20508                                    NotificationId::unique::<OpenPermalinkToLine>(),
20509                                    message,
20510                                ),
20511                                cx,
20512                            )
20513                        })
20514                        .ok();
20515                }
20516            }
20517        })
20518        .detach();
20519    }
20520
20521    pub fn insert_uuid_v4(
20522        &mut self,
20523        _: &InsertUuidV4,
20524        window: &mut Window,
20525        cx: &mut Context<Self>,
20526    ) {
20527        self.insert_uuid(UuidVersion::V4, window, cx);
20528    }
20529
20530    pub fn insert_uuid_v7(
20531        &mut self,
20532        _: &InsertUuidV7,
20533        window: &mut Window,
20534        cx: &mut Context<Self>,
20535    ) {
20536        self.insert_uuid(UuidVersion::V7, window, cx);
20537    }
20538
20539    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
20540        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
20541        self.transact(window, cx, |this, window, cx| {
20542            let edits = this
20543                .selections
20544                .all::<Point>(&this.display_snapshot(cx))
20545                .into_iter()
20546                .map(|selection| {
20547                    let uuid = match version {
20548                        UuidVersion::V4 => uuid::Uuid::new_v4(),
20549                        UuidVersion::V7 => uuid::Uuid::now_v7(),
20550                    };
20551
20552                    (selection.range(), uuid.to_string())
20553                });
20554            this.edit(edits, cx);
20555            this.refresh_edit_prediction(true, false, window, cx);
20556        });
20557    }
20558
20559    pub fn open_selections_in_multibuffer(
20560        &mut self,
20561        _: &OpenSelectionsInMultibuffer,
20562        window: &mut Window,
20563        cx: &mut Context<Self>,
20564    ) {
20565        let multibuffer = self.buffer.read(cx);
20566
20567        let Some(buffer) = multibuffer.as_singleton() else {
20568            return;
20569        };
20570
20571        let Some(workspace) = self.workspace() else {
20572            return;
20573        };
20574
20575        let title = multibuffer.title(cx).to_string();
20576
20577        let locations = self
20578            .selections
20579            .all_anchors(&self.display_snapshot(cx))
20580            .iter()
20581            .map(|selection| {
20582                (
20583                    buffer.clone(),
20584                    (selection.start.text_anchor..selection.end.text_anchor)
20585                        .to_point(buffer.read(cx)),
20586                )
20587            })
20588            .into_group_map();
20589
20590        cx.spawn_in(window, async move |_, cx| {
20591            workspace.update_in(cx, |workspace, window, cx| {
20592                Self::open_locations_in_multibuffer(
20593                    workspace,
20594                    locations,
20595                    format!("Selections for '{title}'"),
20596                    false,
20597                    MultibufferSelectionMode::All,
20598                    window,
20599                    cx,
20600                );
20601            })
20602        })
20603        .detach();
20604    }
20605
20606    /// Adds a row highlight for the given range. If a row has multiple highlights, the
20607    /// last highlight added will be used.
20608    ///
20609    /// If the range ends at the beginning of a line, then that line will not be highlighted.
20610    pub fn highlight_rows<T: 'static>(
20611        &mut self,
20612        range: Range<Anchor>,
20613        color: Hsla,
20614        options: RowHighlightOptions,
20615        cx: &mut Context<Self>,
20616    ) {
20617        let snapshot = self.buffer().read(cx).snapshot(cx);
20618        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
20619        let ix = row_highlights.binary_search_by(|highlight| {
20620            Ordering::Equal
20621                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
20622                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
20623        });
20624
20625        if let Err(mut ix) = ix {
20626            let index = post_inc(&mut self.highlight_order);
20627
20628            // If this range intersects with the preceding highlight, then merge it with
20629            // the preceding highlight. Otherwise insert a new highlight.
20630            let mut merged = false;
20631            if ix > 0 {
20632                let prev_highlight = &mut row_highlights[ix - 1];
20633                if prev_highlight
20634                    .range
20635                    .end
20636                    .cmp(&range.start, &snapshot)
20637                    .is_ge()
20638                {
20639                    ix -= 1;
20640                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
20641                        prev_highlight.range.end = range.end;
20642                    }
20643                    merged = true;
20644                    prev_highlight.index = index;
20645                    prev_highlight.color = color;
20646                    prev_highlight.options = options;
20647                }
20648            }
20649
20650            if !merged {
20651                row_highlights.insert(
20652                    ix,
20653                    RowHighlight {
20654                        range,
20655                        index,
20656                        color,
20657                        options,
20658                        type_id: TypeId::of::<T>(),
20659                    },
20660                );
20661            }
20662
20663            // If any of the following highlights intersect with this one, merge them.
20664            while let Some(next_highlight) = row_highlights.get(ix + 1) {
20665                let highlight = &row_highlights[ix];
20666                if next_highlight
20667                    .range
20668                    .start
20669                    .cmp(&highlight.range.end, &snapshot)
20670                    .is_le()
20671                {
20672                    if next_highlight
20673                        .range
20674                        .end
20675                        .cmp(&highlight.range.end, &snapshot)
20676                        .is_gt()
20677                    {
20678                        row_highlights[ix].range.end = next_highlight.range.end;
20679                    }
20680                    row_highlights.remove(ix + 1);
20681                } else {
20682                    break;
20683                }
20684            }
20685        }
20686    }
20687
20688    /// Remove any highlighted row ranges of the given type that intersect the
20689    /// given ranges.
20690    pub fn remove_highlighted_rows<T: 'static>(
20691        &mut self,
20692        ranges_to_remove: Vec<Range<Anchor>>,
20693        cx: &mut Context<Self>,
20694    ) {
20695        let snapshot = self.buffer().read(cx).snapshot(cx);
20696        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
20697        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
20698        row_highlights.retain(|highlight| {
20699            while let Some(range_to_remove) = ranges_to_remove.peek() {
20700                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
20701                    Ordering::Less | Ordering::Equal => {
20702                        ranges_to_remove.next();
20703                    }
20704                    Ordering::Greater => {
20705                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
20706                            Ordering::Less | Ordering::Equal => {
20707                                return false;
20708                            }
20709                            Ordering::Greater => break,
20710                        }
20711                    }
20712                }
20713            }
20714
20715            true
20716        })
20717    }
20718
20719    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
20720    pub fn clear_row_highlights<T: 'static>(&mut self) {
20721        self.highlighted_rows.remove(&TypeId::of::<T>());
20722    }
20723
20724    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
20725    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
20726        self.highlighted_rows
20727            .get(&TypeId::of::<T>())
20728            .map_or(&[] as &[_], |vec| vec.as_slice())
20729            .iter()
20730            .map(|highlight| (highlight.range.clone(), highlight.color))
20731    }
20732
20733    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
20734    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
20735    /// Allows to ignore certain kinds of highlights.
20736    pub fn highlighted_display_rows(
20737        &self,
20738        window: &mut Window,
20739        cx: &mut App,
20740    ) -> BTreeMap<DisplayRow, LineHighlight> {
20741        let snapshot = self.snapshot(window, cx);
20742        let mut used_highlight_orders = HashMap::default();
20743        self.highlighted_rows
20744            .iter()
20745            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
20746            .fold(
20747                BTreeMap::<DisplayRow, LineHighlight>::new(),
20748                |mut unique_rows, highlight| {
20749                    let start = highlight.range.start.to_display_point(&snapshot);
20750                    let end = highlight.range.end.to_display_point(&snapshot);
20751                    let start_row = start.row().0;
20752                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
20753                        && end.column() == 0
20754                    {
20755                        end.row().0.saturating_sub(1)
20756                    } else {
20757                        end.row().0
20758                    };
20759                    for row in start_row..=end_row {
20760                        let used_index =
20761                            used_highlight_orders.entry(row).or_insert(highlight.index);
20762                        if highlight.index >= *used_index {
20763                            *used_index = highlight.index;
20764                            unique_rows.insert(
20765                                DisplayRow(row),
20766                                LineHighlight {
20767                                    include_gutter: highlight.options.include_gutter,
20768                                    border: None,
20769                                    background: highlight.color.into(),
20770                                    type_id: Some(highlight.type_id),
20771                                },
20772                            );
20773                        }
20774                    }
20775                    unique_rows
20776                },
20777            )
20778    }
20779
20780    pub fn highlighted_display_row_for_autoscroll(
20781        &self,
20782        snapshot: &DisplaySnapshot,
20783    ) -> Option<DisplayRow> {
20784        self.highlighted_rows
20785            .values()
20786            .flat_map(|highlighted_rows| highlighted_rows.iter())
20787            .filter_map(|highlight| {
20788                if highlight.options.autoscroll {
20789                    Some(highlight.range.start.to_display_point(snapshot).row())
20790                } else {
20791                    None
20792                }
20793            })
20794            .min()
20795    }
20796
20797    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
20798        self.highlight_background::<SearchWithinRange>(
20799            ranges,
20800            |colors| colors.colors().editor_document_highlight_read_background,
20801            cx,
20802        )
20803    }
20804
20805    pub fn set_breadcrumb_header(&mut self, new_header: String) {
20806        self.breadcrumb_header = Some(new_header);
20807    }
20808
20809    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
20810        self.clear_background_highlights::<SearchWithinRange>(cx);
20811    }
20812
20813    pub fn highlight_background<T: 'static>(
20814        &mut self,
20815        ranges: &[Range<Anchor>],
20816        color_fetcher: fn(&Theme) -> Hsla,
20817        cx: &mut Context<Self>,
20818    ) {
20819        self.background_highlights.insert(
20820            HighlightKey::Type(TypeId::of::<T>()),
20821            (color_fetcher, Arc::from(ranges)),
20822        );
20823        self.scrollbar_marker_state.dirty = true;
20824        cx.notify();
20825    }
20826
20827    pub fn highlight_background_key<T: 'static>(
20828        &mut self,
20829        key: usize,
20830        ranges: &[Range<Anchor>],
20831        color_fetcher: fn(&Theme) -> Hsla,
20832        cx: &mut Context<Self>,
20833    ) {
20834        self.background_highlights.insert(
20835            HighlightKey::TypePlus(TypeId::of::<T>(), key),
20836            (color_fetcher, Arc::from(ranges)),
20837        );
20838        self.scrollbar_marker_state.dirty = true;
20839        cx.notify();
20840    }
20841
20842    pub fn clear_background_highlights<T: 'static>(
20843        &mut self,
20844        cx: &mut Context<Self>,
20845    ) -> Option<BackgroundHighlight> {
20846        let text_highlights = self
20847            .background_highlights
20848            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
20849        if !text_highlights.1.is_empty() {
20850            self.scrollbar_marker_state.dirty = true;
20851            cx.notify();
20852        }
20853        Some(text_highlights)
20854    }
20855
20856    pub fn highlight_gutter<T: 'static>(
20857        &mut self,
20858        ranges: impl Into<Vec<Range<Anchor>>>,
20859        color_fetcher: fn(&App) -> Hsla,
20860        cx: &mut Context<Self>,
20861    ) {
20862        self.gutter_highlights
20863            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
20864        cx.notify();
20865    }
20866
20867    pub fn clear_gutter_highlights<T: 'static>(
20868        &mut self,
20869        cx: &mut Context<Self>,
20870    ) -> Option<GutterHighlight> {
20871        cx.notify();
20872        self.gutter_highlights.remove(&TypeId::of::<T>())
20873    }
20874
20875    pub fn insert_gutter_highlight<T: 'static>(
20876        &mut self,
20877        range: Range<Anchor>,
20878        color_fetcher: fn(&App) -> Hsla,
20879        cx: &mut Context<Self>,
20880    ) {
20881        let snapshot = self.buffer().read(cx).snapshot(cx);
20882        let mut highlights = self
20883            .gutter_highlights
20884            .remove(&TypeId::of::<T>())
20885            .map(|(_, highlights)| highlights)
20886            .unwrap_or_default();
20887        let ix = highlights.binary_search_by(|highlight| {
20888            Ordering::Equal
20889                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
20890                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
20891        });
20892        if let Err(ix) = ix {
20893            highlights.insert(ix, range);
20894        }
20895        self.gutter_highlights
20896            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
20897    }
20898
20899    pub fn remove_gutter_highlights<T: 'static>(
20900        &mut self,
20901        ranges_to_remove: Vec<Range<Anchor>>,
20902        cx: &mut Context<Self>,
20903    ) {
20904        let snapshot = self.buffer().read(cx).snapshot(cx);
20905        let Some((color_fetcher, mut gutter_highlights)) =
20906            self.gutter_highlights.remove(&TypeId::of::<T>())
20907        else {
20908            return;
20909        };
20910        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
20911        gutter_highlights.retain(|highlight| {
20912            while let Some(range_to_remove) = ranges_to_remove.peek() {
20913                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
20914                    Ordering::Less | Ordering::Equal => {
20915                        ranges_to_remove.next();
20916                    }
20917                    Ordering::Greater => {
20918                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
20919                            Ordering::Less | Ordering::Equal => {
20920                                return false;
20921                            }
20922                            Ordering::Greater => break,
20923                        }
20924                    }
20925                }
20926            }
20927
20928            true
20929        });
20930        self.gutter_highlights
20931            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
20932    }
20933
20934    #[cfg(feature = "test-support")]
20935    pub fn all_text_highlights(
20936        &self,
20937        window: &mut Window,
20938        cx: &mut Context<Self>,
20939    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
20940        let snapshot = self.snapshot(window, cx);
20941        self.display_map.update(cx, |display_map, _| {
20942            display_map
20943                .all_text_highlights()
20944                .map(|highlight| {
20945                    let (style, ranges) = highlight.as_ref();
20946                    (
20947                        *style,
20948                        ranges
20949                            .iter()
20950                            .map(|range| range.clone().to_display_points(&snapshot))
20951                            .collect(),
20952                    )
20953                })
20954                .collect()
20955        })
20956    }
20957
20958    #[cfg(feature = "test-support")]
20959    pub fn all_text_background_highlights(
20960        &self,
20961        window: &mut Window,
20962        cx: &mut Context<Self>,
20963    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20964        let snapshot = self.snapshot(window, cx);
20965        let buffer = &snapshot.buffer_snapshot();
20966        let start = buffer.anchor_before(MultiBufferOffset(0));
20967        let end = buffer.anchor_after(buffer.len());
20968        self.sorted_background_highlights_in_range(start..end, &snapshot, cx.theme())
20969    }
20970
20971    #[cfg(any(test, feature = "test-support"))]
20972    pub fn sorted_background_highlights_in_range(
20973        &self,
20974        search_range: Range<Anchor>,
20975        display_snapshot: &DisplaySnapshot,
20976        theme: &Theme,
20977    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20978        let mut res = self.background_highlights_in_range(search_range, display_snapshot, theme);
20979        res.sort_by(|a, b| {
20980            a.0.start
20981                .cmp(&b.0.start)
20982                .then_with(|| a.0.end.cmp(&b.0.end))
20983                .then_with(|| a.1.cmp(&b.1))
20984        });
20985        res
20986    }
20987
20988    #[cfg(feature = "test-support")]
20989    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
20990        let snapshot = self.buffer().read(cx).snapshot(cx);
20991
20992        let highlights = self
20993            .background_highlights
20994            .get(&HighlightKey::Type(TypeId::of::<
20995                items::BufferSearchHighlights,
20996            >()));
20997
20998        if let Some((_color, ranges)) = highlights {
20999            ranges
21000                .iter()
21001                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
21002                .collect_vec()
21003        } else {
21004            vec![]
21005        }
21006    }
21007
21008    fn document_highlights_for_position<'a>(
21009        &'a self,
21010        position: Anchor,
21011        buffer: &'a MultiBufferSnapshot,
21012    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
21013        let read_highlights = self
21014            .background_highlights
21015            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
21016            .map(|h| &h.1);
21017        let write_highlights = self
21018            .background_highlights
21019            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
21020            .map(|h| &h.1);
21021        let left_position = position.bias_left(buffer);
21022        let right_position = position.bias_right(buffer);
21023        read_highlights
21024            .into_iter()
21025            .chain(write_highlights)
21026            .flat_map(move |ranges| {
21027                let start_ix = match ranges.binary_search_by(|probe| {
21028                    let cmp = probe.end.cmp(&left_position, buffer);
21029                    if cmp.is_ge() {
21030                        Ordering::Greater
21031                    } else {
21032                        Ordering::Less
21033                    }
21034                }) {
21035                    Ok(i) | Err(i) => i,
21036                };
21037
21038                ranges[start_ix..]
21039                    .iter()
21040                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
21041            })
21042    }
21043
21044    pub fn has_background_highlights<T: 'static>(&self) -> bool {
21045        self.background_highlights
21046            .get(&HighlightKey::Type(TypeId::of::<T>()))
21047            .is_some_and(|(_, highlights)| !highlights.is_empty())
21048    }
21049
21050    /// Returns all background highlights for a given range.
21051    ///
21052    /// The order of highlights is not deterministic, do sort the ranges if needed for the logic.
21053    pub fn background_highlights_in_range(
21054        &self,
21055        search_range: Range<Anchor>,
21056        display_snapshot: &DisplaySnapshot,
21057        theme: &Theme,
21058    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
21059        let mut results = Vec::new();
21060        for (color_fetcher, ranges) in self.background_highlights.values() {
21061            let color = color_fetcher(theme);
21062            let start_ix = match ranges.binary_search_by(|probe| {
21063                let cmp = probe
21064                    .end
21065                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
21066                if cmp.is_gt() {
21067                    Ordering::Greater
21068                } else {
21069                    Ordering::Less
21070                }
21071            }) {
21072                Ok(i) | Err(i) => i,
21073            };
21074            for range in &ranges[start_ix..] {
21075                if range
21076                    .start
21077                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
21078                    .is_ge()
21079                {
21080                    break;
21081                }
21082
21083                let start = range.start.to_display_point(display_snapshot);
21084                let end = range.end.to_display_point(display_snapshot);
21085                results.push((start..end, color))
21086            }
21087        }
21088        results
21089    }
21090
21091    pub fn gutter_highlights_in_range(
21092        &self,
21093        search_range: Range<Anchor>,
21094        display_snapshot: &DisplaySnapshot,
21095        cx: &App,
21096    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
21097        let mut results = Vec::new();
21098        for (color_fetcher, ranges) in self.gutter_highlights.values() {
21099            let color = color_fetcher(cx);
21100            let start_ix = match ranges.binary_search_by(|probe| {
21101                let cmp = probe
21102                    .end
21103                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
21104                if cmp.is_gt() {
21105                    Ordering::Greater
21106                } else {
21107                    Ordering::Less
21108                }
21109            }) {
21110                Ok(i) | Err(i) => i,
21111            };
21112            for range in &ranges[start_ix..] {
21113                if range
21114                    .start
21115                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
21116                    .is_ge()
21117                {
21118                    break;
21119                }
21120
21121                let start = range.start.to_display_point(display_snapshot);
21122                let end = range.end.to_display_point(display_snapshot);
21123                results.push((start..end, color))
21124            }
21125        }
21126        results
21127    }
21128
21129    /// Get the text ranges corresponding to the redaction query
21130    pub fn redacted_ranges(
21131        &self,
21132        search_range: Range<Anchor>,
21133        display_snapshot: &DisplaySnapshot,
21134        cx: &App,
21135    ) -> Vec<Range<DisplayPoint>> {
21136        display_snapshot
21137            .buffer_snapshot()
21138            .redacted_ranges(search_range, |file| {
21139                if let Some(file) = file {
21140                    file.is_private()
21141                        && EditorSettings::get(
21142                            Some(SettingsLocation {
21143                                worktree_id: file.worktree_id(cx),
21144                                path: file.path().as_ref(),
21145                            }),
21146                            cx,
21147                        )
21148                        .redact_private_values
21149                } else {
21150                    false
21151                }
21152            })
21153            .map(|range| {
21154                range.start.to_display_point(display_snapshot)
21155                    ..range.end.to_display_point(display_snapshot)
21156            })
21157            .collect()
21158    }
21159
21160    pub fn highlight_text_key<T: 'static>(
21161        &mut self,
21162        key: usize,
21163        ranges: Vec<Range<Anchor>>,
21164        style: HighlightStyle,
21165        cx: &mut Context<Self>,
21166    ) {
21167        self.display_map.update(cx, |map, _| {
21168            map.highlight_text(
21169                HighlightKey::TypePlus(TypeId::of::<T>(), key),
21170                ranges,
21171                style,
21172            );
21173        });
21174        cx.notify();
21175    }
21176
21177    pub fn highlight_text<T: 'static>(
21178        &mut self,
21179        ranges: Vec<Range<Anchor>>,
21180        style: HighlightStyle,
21181        cx: &mut Context<Self>,
21182    ) {
21183        self.display_map.update(cx, |map, _| {
21184            map.highlight_text(HighlightKey::Type(TypeId::of::<T>()), ranges, style)
21185        });
21186        cx.notify();
21187    }
21188
21189    pub fn text_highlights<'a, T: 'static>(
21190        &'a self,
21191        cx: &'a App,
21192    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
21193        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
21194    }
21195
21196    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
21197        let cleared = self
21198            .display_map
21199            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
21200        if cleared {
21201            cx.notify();
21202        }
21203    }
21204
21205    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
21206        (self.read_only(cx) || self.blink_manager.read(cx).visible())
21207            && self.focus_handle.is_focused(window)
21208    }
21209
21210    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
21211        self.show_cursor_when_unfocused = is_enabled;
21212        cx.notify();
21213    }
21214
21215    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
21216        cx.notify();
21217    }
21218
21219    fn on_debug_session_event(
21220        &mut self,
21221        _session: Entity<Session>,
21222        event: &SessionEvent,
21223        cx: &mut Context<Self>,
21224    ) {
21225        if let SessionEvent::InvalidateInlineValue = event {
21226            self.refresh_inline_values(cx);
21227        }
21228    }
21229
21230    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
21231        let Some(project) = self.project.clone() else {
21232            return;
21233        };
21234
21235        if !self.inline_value_cache.enabled {
21236            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
21237            self.splice_inlays(&inlays, Vec::new(), cx);
21238            return;
21239        }
21240
21241        let current_execution_position = self
21242            .highlighted_rows
21243            .get(&TypeId::of::<ActiveDebugLine>())
21244            .and_then(|lines| lines.last().map(|line| line.range.end));
21245
21246        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
21247            let inline_values = editor
21248                .update(cx, |editor, cx| {
21249                    let Some(current_execution_position) = current_execution_position else {
21250                        return Some(Task::ready(Ok(Vec::new())));
21251                    };
21252
21253                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
21254                        let snapshot = buffer.snapshot(cx);
21255
21256                        let excerpt = snapshot.excerpt_containing(
21257                            current_execution_position..current_execution_position,
21258                        )?;
21259
21260                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
21261                    })?;
21262
21263                    let range =
21264                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
21265
21266                    project.inline_values(buffer, range, cx)
21267                })
21268                .ok()
21269                .flatten()?
21270                .await
21271                .context("refreshing debugger inlays")
21272                .log_err()?;
21273
21274            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
21275
21276            for (buffer_id, inline_value) in inline_values
21277                .into_iter()
21278                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
21279            {
21280                buffer_inline_values
21281                    .entry(buffer_id)
21282                    .or_default()
21283                    .push(inline_value);
21284            }
21285
21286            editor
21287                .update(cx, |editor, cx| {
21288                    let snapshot = editor.buffer.read(cx).snapshot(cx);
21289                    let mut new_inlays = Vec::default();
21290
21291                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
21292                        let buffer_id = buffer_snapshot.remote_id();
21293                        buffer_inline_values
21294                            .get(&buffer_id)
21295                            .into_iter()
21296                            .flatten()
21297                            .for_each(|hint| {
21298                                let inlay = Inlay::debugger(
21299                                    post_inc(&mut editor.next_inlay_id),
21300                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
21301                                    hint.text(),
21302                                );
21303                                if !inlay.text().chars().contains(&'\n') {
21304                                    new_inlays.push(inlay);
21305                                }
21306                            });
21307                    }
21308
21309                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
21310                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
21311
21312                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
21313                })
21314                .ok()?;
21315            Some(())
21316        });
21317    }
21318
21319    fn on_buffer_event(
21320        &mut self,
21321        multibuffer: &Entity<MultiBuffer>,
21322        event: &multi_buffer::Event,
21323        window: &mut Window,
21324        cx: &mut Context<Self>,
21325    ) {
21326        match event {
21327            multi_buffer::Event::Edited { edited_buffer } => {
21328                self.scrollbar_marker_state.dirty = true;
21329                self.active_indent_guides_state.dirty = true;
21330                self.refresh_active_diagnostics(cx);
21331                self.refresh_code_actions(window, cx);
21332                self.refresh_selected_text_highlights(true, window, cx);
21333                self.refresh_single_line_folds(window, cx);
21334                self.refresh_matching_bracket_highlights(window, cx);
21335                if self.has_active_edit_prediction() {
21336                    self.update_visible_edit_prediction(window, cx);
21337                }
21338
21339                if let Some(buffer) = edited_buffer {
21340                    if buffer.read(cx).file().is_none() {
21341                        cx.emit(EditorEvent::TitleChanged);
21342                    }
21343
21344                    if self.project.is_some() {
21345                        let buffer_id = buffer.read(cx).remote_id();
21346                        self.register_buffer(buffer_id, cx);
21347                        self.update_lsp_data(Some(buffer_id), window, cx);
21348                        self.refresh_inlay_hints(
21349                            InlayHintRefreshReason::BufferEdited(buffer_id),
21350                            cx,
21351                        );
21352                    }
21353                }
21354
21355                cx.emit(EditorEvent::BufferEdited);
21356                cx.emit(SearchEvent::MatchesInvalidated);
21357
21358                let Some(project) = &self.project else { return };
21359                let (telemetry, is_via_ssh) = {
21360                    let project = project.read(cx);
21361                    let telemetry = project.client().telemetry().clone();
21362                    let is_via_ssh = project.is_via_remote_server();
21363                    (telemetry, is_via_ssh)
21364                };
21365                telemetry.log_edit_event("editor", is_via_ssh);
21366            }
21367            multi_buffer::Event::ExcerptsAdded {
21368                buffer,
21369                predecessor,
21370                excerpts,
21371            } => {
21372                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21373                let buffer_id = buffer.read(cx).remote_id();
21374                if self.buffer.read(cx).diff_for(buffer_id).is_none()
21375                    && let Some(project) = &self.project
21376                {
21377                    update_uncommitted_diff_for_buffer(
21378                        cx.entity(),
21379                        project,
21380                        [buffer.clone()],
21381                        self.buffer.clone(),
21382                        cx,
21383                    )
21384                    .detach();
21385                }
21386                self.update_lsp_data(Some(buffer_id), window, cx);
21387                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
21388                cx.emit(EditorEvent::ExcerptsAdded {
21389                    buffer: buffer.clone(),
21390                    predecessor: *predecessor,
21391                    excerpts: excerpts.clone(),
21392                });
21393            }
21394            multi_buffer::Event::ExcerptsRemoved {
21395                ids,
21396                removed_buffer_ids,
21397            } => {
21398                if let Some(inlay_hints) = &mut self.inlay_hints {
21399                    inlay_hints.remove_inlay_chunk_data(removed_buffer_ids);
21400                }
21401                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
21402                for buffer_id in removed_buffer_ids {
21403                    self.registered_buffers.remove(buffer_id);
21404                }
21405                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
21406                cx.emit(EditorEvent::ExcerptsRemoved {
21407                    ids: ids.clone(),
21408                    removed_buffer_ids: removed_buffer_ids.clone(),
21409                });
21410            }
21411            multi_buffer::Event::ExcerptsEdited {
21412                excerpt_ids,
21413                buffer_ids,
21414            } => {
21415                self.display_map.update(cx, |map, cx| {
21416                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
21417                });
21418                cx.emit(EditorEvent::ExcerptsEdited {
21419                    ids: excerpt_ids.clone(),
21420                });
21421            }
21422            multi_buffer::Event::ExcerptsExpanded { ids } => {
21423                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
21424                self.refresh_document_highlights(cx);
21425                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
21426            }
21427            multi_buffer::Event::Reparsed(buffer_id) => {
21428                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21429                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
21430
21431                cx.emit(EditorEvent::Reparsed(*buffer_id));
21432            }
21433            multi_buffer::Event::DiffHunksToggled => {
21434                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21435            }
21436            multi_buffer::Event::LanguageChanged(buffer_id) => {
21437                self.registered_buffers.remove(&buffer_id);
21438                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
21439                cx.emit(EditorEvent::Reparsed(*buffer_id));
21440                cx.notify();
21441            }
21442            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
21443            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
21444            multi_buffer::Event::FileHandleChanged
21445            | multi_buffer::Event::Reloaded
21446            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
21447            multi_buffer::Event::DiagnosticsUpdated => {
21448                self.update_diagnostics_state(window, cx);
21449            }
21450            _ => {}
21451        };
21452    }
21453
21454    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
21455        if !self.diagnostics_enabled() {
21456            return;
21457        }
21458        self.refresh_active_diagnostics(cx);
21459        self.refresh_inline_diagnostics(true, window, cx);
21460        self.scrollbar_marker_state.dirty = true;
21461        cx.notify();
21462    }
21463
21464    pub fn start_temporary_diff_override(&mut self) {
21465        self.load_diff_task.take();
21466        self.temporary_diff_override = true;
21467    }
21468
21469    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
21470        self.temporary_diff_override = false;
21471        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
21472        self.buffer.update(cx, |buffer, cx| {
21473            buffer.set_all_diff_hunks_collapsed(cx);
21474        });
21475
21476        if let Some(project) = self.project.clone() {
21477            self.load_diff_task = Some(
21478                update_uncommitted_diff_for_buffer(
21479                    cx.entity(),
21480                    &project,
21481                    self.buffer.read(cx).all_buffers(),
21482                    self.buffer.clone(),
21483                    cx,
21484                )
21485                .shared(),
21486            );
21487        }
21488    }
21489
21490    fn on_display_map_changed(
21491        &mut self,
21492        _: Entity<DisplayMap>,
21493        _: &mut Window,
21494        cx: &mut Context<Self>,
21495    ) {
21496        cx.notify();
21497    }
21498
21499    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21500        if self.diagnostics_enabled() {
21501            let new_severity = EditorSettings::get_global(cx)
21502                .diagnostics_max_severity
21503                .unwrap_or(DiagnosticSeverity::Hint);
21504            self.set_max_diagnostics_severity(new_severity, cx);
21505        }
21506        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21507        self.update_edit_prediction_settings(cx);
21508        self.refresh_edit_prediction(true, false, window, cx);
21509        self.refresh_inline_values(cx);
21510        self.refresh_inlay_hints(
21511            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
21512                self.selections.newest_anchor().head(),
21513                &self.buffer.read(cx).snapshot(cx),
21514                cx,
21515            )),
21516            cx,
21517        );
21518
21519        let old_cursor_shape = self.cursor_shape;
21520        let old_show_breadcrumbs = self.show_breadcrumbs;
21521
21522        {
21523            let editor_settings = EditorSettings::get_global(cx);
21524            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
21525            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
21526            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
21527            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
21528        }
21529
21530        if old_cursor_shape != self.cursor_shape {
21531            cx.emit(EditorEvent::CursorShapeChanged);
21532        }
21533
21534        if old_show_breadcrumbs != self.show_breadcrumbs {
21535            cx.emit(EditorEvent::BreadcrumbsChanged);
21536        }
21537
21538        let project_settings = ProjectSettings::get_global(cx);
21539        self.buffer_serialization = self
21540            .should_serialize_buffer()
21541            .then(|| BufferSerialization::new(project_settings.session.restore_unsaved_buffers));
21542
21543        if self.mode.is_full() {
21544            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
21545            let inline_blame_enabled = project_settings.git.inline_blame.enabled;
21546            if self.show_inline_diagnostics != show_inline_diagnostics {
21547                self.show_inline_diagnostics = show_inline_diagnostics;
21548                self.refresh_inline_diagnostics(false, window, cx);
21549            }
21550
21551            if self.git_blame_inline_enabled != inline_blame_enabled {
21552                self.toggle_git_blame_inline_internal(false, window, cx);
21553            }
21554
21555            let minimap_settings = EditorSettings::get_global(cx).minimap;
21556            if self.minimap_visibility != MinimapVisibility::Disabled {
21557                if self.minimap_visibility.settings_visibility()
21558                    != minimap_settings.minimap_enabled()
21559                {
21560                    self.set_minimap_visibility(
21561                        MinimapVisibility::for_mode(self.mode(), cx),
21562                        window,
21563                        cx,
21564                    );
21565                } else if let Some(minimap_entity) = self.minimap.as_ref() {
21566                    minimap_entity.update(cx, |minimap_editor, cx| {
21567                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
21568                    })
21569                }
21570            }
21571        }
21572
21573        if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
21574            colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
21575        }) {
21576            if !inlay_splice.is_empty() {
21577                self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
21578            }
21579            self.refresh_colors_for_visible_range(None, window, cx);
21580        }
21581
21582        cx.notify();
21583    }
21584
21585    pub fn set_searchable(&mut self, searchable: bool) {
21586        self.searchable = searchable;
21587    }
21588
21589    pub fn searchable(&self) -> bool {
21590        self.searchable
21591    }
21592
21593    pub fn open_excerpts_in_split(
21594        &mut self,
21595        _: &OpenExcerptsSplit,
21596        window: &mut Window,
21597        cx: &mut Context<Self>,
21598    ) {
21599        self.open_excerpts_common(None, true, window, cx)
21600    }
21601
21602    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
21603        self.open_excerpts_common(None, false, window, cx)
21604    }
21605
21606    fn open_excerpts_common(
21607        &mut self,
21608        jump_data: Option<JumpData>,
21609        split: bool,
21610        window: &mut Window,
21611        cx: &mut Context<Self>,
21612    ) {
21613        let Some(workspace) = self.workspace() else {
21614            cx.propagate();
21615            return;
21616        };
21617
21618        if self.buffer.read(cx).is_singleton() {
21619            cx.propagate();
21620            return;
21621        }
21622
21623        let mut new_selections_by_buffer = HashMap::default();
21624        match &jump_data {
21625            Some(JumpData::MultiBufferPoint {
21626                excerpt_id,
21627                position,
21628                anchor,
21629                line_offset_from_top,
21630            }) => {
21631                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
21632                if let Some(buffer) = multi_buffer_snapshot
21633                    .buffer_id_for_excerpt(*excerpt_id)
21634                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
21635                {
21636                    let buffer_snapshot = buffer.read(cx).snapshot();
21637                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
21638                        language::ToPoint::to_point(anchor, &buffer_snapshot)
21639                    } else {
21640                        buffer_snapshot.clip_point(*position, Bias::Left)
21641                    };
21642                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
21643                    new_selections_by_buffer.insert(
21644                        buffer,
21645                        (
21646                            vec![BufferOffset(jump_to_offset)..BufferOffset(jump_to_offset)],
21647                            Some(*line_offset_from_top),
21648                        ),
21649                    );
21650                }
21651            }
21652            Some(JumpData::MultiBufferRow {
21653                row,
21654                line_offset_from_top,
21655            }) => {
21656                let point = MultiBufferPoint::new(row.0, 0);
21657                if let Some((buffer, buffer_point, _)) =
21658                    self.buffer.read(cx).point_to_buffer_point(point, cx)
21659                {
21660                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
21661                    new_selections_by_buffer
21662                        .entry(buffer)
21663                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
21664                        .0
21665                        .push(BufferOffset(buffer_offset)..BufferOffset(buffer_offset))
21666                }
21667            }
21668            None => {
21669                let selections = self
21670                    .selections
21671                    .all::<MultiBufferOffset>(&self.display_snapshot(cx));
21672                let multi_buffer = self.buffer.read(cx);
21673                for selection in selections {
21674                    for (snapshot, range, _, anchor) in multi_buffer
21675                        .snapshot(cx)
21676                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
21677                    {
21678                        if let Some(anchor) = anchor {
21679                            let Some(buffer_handle) = multi_buffer.buffer_for_anchor(anchor, cx)
21680                            else {
21681                                continue;
21682                            };
21683                            let offset = text::ToOffset::to_offset(
21684                                &anchor.text_anchor,
21685                                &buffer_handle.read(cx).snapshot(),
21686                            );
21687                            let range = BufferOffset(offset)..BufferOffset(offset);
21688                            new_selections_by_buffer
21689                                .entry(buffer_handle)
21690                                .or_insert((Vec::new(), None))
21691                                .0
21692                                .push(range)
21693                        } else {
21694                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
21695                            else {
21696                                continue;
21697                            };
21698                            new_selections_by_buffer
21699                                .entry(buffer_handle)
21700                                .or_insert((Vec::new(), None))
21701                                .0
21702                                .push(range)
21703                        }
21704                    }
21705                }
21706            }
21707        }
21708
21709        new_selections_by_buffer
21710            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
21711
21712        if new_selections_by_buffer.is_empty() {
21713            return;
21714        }
21715
21716        // We defer the pane interaction because we ourselves are a workspace item
21717        // and activating a new item causes the pane to call a method on us reentrantly,
21718        // which panics if we're on the stack.
21719        window.defer(cx, move |window, cx| {
21720            workspace.update(cx, |workspace, cx| {
21721                let pane = if split {
21722                    workspace.adjacent_pane(window, cx)
21723                } else {
21724                    workspace.active_pane().clone()
21725                };
21726
21727                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
21728                    let editor = buffer
21729                        .read(cx)
21730                        .file()
21731                        .is_none()
21732                        .then(|| {
21733                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
21734                            // so `workspace.open_project_item` will never find them, always opening a new editor.
21735                            // Instead, we try to activate the existing editor in the pane first.
21736                            let (editor, pane_item_index) =
21737                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
21738                                    let editor = item.downcast::<Editor>()?;
21739                                    let singleton_buffer =
21740                                        editor.read(cx).buffer().read(cx).as_singleton()?;
21741                                    if singleton_buffer == buffer {
21742                                        Some((editor, i))
21743                                    } else {
21744                                        None
21745                                    }
21746                                })?;
21747                            pane.update(cx, |pane, cx| {
21748                                pane.activate_item(pane_item_index, true, true, window, cx)
21749                            });
21750                            Some(editor)
21751                        })
21752                        .flatten()
21753                        .unwrap_or_else(|| {
21754                            workspace.open_project_item::<Self>(
21755                                pane.clone(),
21756                                buffer,
21757                                true,
21758                                true,
21759                                window,
21760                                cx,
21761                            )
21762                        });
21763
21764                    editor.update(cx, |editor, cx| {
21765                        let autoscroll = match scroll_offset {
21766                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
21767                            None => Autoscroll::newest(),
21768                        };
21769                        let nav_history = editor.nav_history.take();
21770                        editor.change_selections(
21771                            SelectionEffects::scroll(autoscroll),
21772                            window,
21773                            cx,
21774                            |s| {
21775                                s.select_ranges(ranges.into_iter().map(|range| {
21776                                    // we checked that the editor is a singleton editor so the offsets are valid
21777                                    MultiBufferOffset(range.start.0)..MultiBufferOffset(range.end.0)
21778                                }));
21779                            },
21780                        );
21781                        editor.nav_history = nav_history;
21782                    });
21783                }
21784            })
21785        });
21786    }
21787
21788    // For now, don't allow opening excerpts in buffers that aren't backed by
21789    // regular project files.
21790    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
21791        file.is_none_or(|file| project::File::from_dyn(Some(file)).is_some())
21792    }
21793
21794    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<MultiBufferOffsetUtf16>>> {
21795        let snapshot = self.buffer.read(cx).read(cx);
21796        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
21797        Some(
21798            ranges
21799                .iter()
21800                .map(move |range| {
21801                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
21802                })
21803                .collect(),
21804        )
21805    }
21806
21807    fn selection_replacement_ranges(
21808        &self,
21809        range: Range<MultiBufferOffsetUtf16>,
21810        cx: &mut App,
21811    ) -> Vec<Range<MultiBufferOffsetUtf16>> {
21812        let selections = self
21813            .selections
21814            .all::<MultiBufferOffsetUtf16>(&self.display_snapshot(cx));
21815        let newest_selection = selections
21816            .iter()
21817            .max_by_key(|selection| selection.id)
21818            .unwrap();
21819        let start_delta = range.start.0.0 as isize - newest_selection.start.0.0 as isize;
21820        let end_delta = range.end.0.0 as isize - newest_selection.end.0.0 as isize;
21821        let snapshot = self.buffer.read(cx).read(cx);
21822        selections
21823            .into_iter()
21824            .map(|mut selection| {
21825                selection.start.0.0 =
21826                    (selection.start.0.0 as isize).saturating_add(start_delta) as usize;
21827                selection.end.0.0 = (selection.end.0.0 as isize).saturating_add(end_delta) as usize;
21828                snapshot.clip_offset_utf16(selection.start, Bias::Left)
21829                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
21830            })
21831            .collect()
21832    }
21833
21834    fn report_editor_event(
21835        &self,
21836        reported_event: ReportEditorEvent,
21837        file_extension: Option<String>,
21838        cx: &App,
21839    ) {
21840        if cfg!(any(test, feature = "test-support")) {
21841            return;
21842        }
21843
21844        let Some(project) = &self.project else { return };
21845
21846        // If None, we are in a file without an extension
21847        let file = self
21848            .buffer
21849            .read(cx)
21850            .as_singleton()
21851            .and_then(|b| b.read(cx).file());
21852        let file_extension = file_extension.or(file
21853            .as_ref()
21854            .and_then(|file| Path::new(file.file_name(cx)).extension())
21855            .and_then(|e| e.to_str())
21856            .map(|a| a.to_string()));
21857
21858        let vim_mode = vim_mode_setting::VimModeSetting::try_get(cx)
21859            .map(|vim_mode| vim_mode.0)
21860            .unwrap_or(false);
21861
21862        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
21863        let copilot_enabled = edit_predictions_provider
21864            == language::language_settings::EditPredictionProvider::Copilot;
21865        let copilot_enabled_for_language = self
21866            .buffer
21867            .read(cx)
21868            .language_settings(cx)
21869            .show_edit_predictions;
21870
21871        let project = project.read(cx);
21872        let event_type = reported_event.event_type();
21873
21874        if let ReportEditorEvent::Saved { auto_saved } = reported_event {
21875            telemetry::event!(
21876                event_type,
21877                type = if auto_saved {"autosave"} else {"manual"},
21878                file_extension,
21879                vim_mode,
21880                copilot_enabled,
21881                copilot_enabled_for_language,
21882                edit_predictions_provider,
21883                is_via_ssh = project.is_via_remote_server(),
21884            );
21885        } else {
21886            telemetry::event!(
21887                event_type,
21888                file_extension,
21889                vim_mode,
21890                copilot_enabled,
21891                copilot_enabled_for_language,
21892                edit_predictions_provider,
21893                is_via_ssh = project.is_via_remote_server(),
21894            );
21895        };
21896    }
21897
21898    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
21899    /// with each line being an array of {text, highlight} objects.
21900    fn copy_highlight_json(
21901        &mut self,
21902        _: &CopyHighlightJson,
21903        window: &mut Window,
21904        cx: &mut Context<Self>,
21905    ) {
21906        #[derive(Serialize)]
21907        struct Chunk<'a> {
21908            text: String,
21909            highlight: Option<&'a str>,
21910        }
21911
21912        let snapshot = self.buffer.read(cx).snapshot(cx);
21913        let range = self
21914            .selected_text_range(false, window, cx)
21915            .and_then(|selection| {
21916                if selection.range.is_empty() {
21917                    None
21918                } else {
21919                    Some(
21920                        snapshot.offset_utf16_to_offset(MultiBufferOffsetUtf16(OffsetUtf16(
21921                            selection.range.start,
21922                        )))
21923                            ..snapshot.offset_utf16_to_offset(MultiBufferOffsetUtf16(OffsetUtf16(
21924                                selection.range.end,
21925                            ))),
21926                    )
21927                }
21928            })
21929            .unwrap_or_else(|| MultiBufferOffset(0)..snapshot.len());
21930
21931        let chunks = snapshot.chunks(range, true);
21932        let mut lines = Vec::new();
21933        let mut line: VecDeque<Chunk> = VecDeque::new();
21934
21935        let Some(style) = self.style.as_ref() else {
21936            return;
21937        };
21938
21939        for chunk in chunks {
21940            let highlight = chunk
21941                .syntax_highlight_id
21942                .and_then(|id| id.name(&style.syntax));
21943            let mut chunk_lines = chunk.text.split('\n').peekable();
21944            while let Some(text) = chunk_lines.next() {
21945                let mut merged_with_last_token = false;
21946                if let Some(last_token) = line.back_mut()
21947                    && last_token.highlight == highlight
21948                {
21949                    last_token.text.push_str(text);
21950                    merged_with_last_token = true;
21951                }
21952
21953                if !merged_with_last_token {
21954                    line.push_back(Chunk {
21955                        text: text.into(),
21956                        highlight,
21957                    });
21958                }
21959
21960                if chunk_lines.peek().is_some() {
21961                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
21962                        line.pop_front();
21963                    }
21964                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
21965                        line.pop_back();
21966                    }
21967
21968                    lines.push(mem::take(&mut line));
21969                }
21970            }
21971        }
21972
21973        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
21974            return;
21975        };
21976        cx.write_to_clipboard(ClipboardItem::new_string(lines));
21977    }
21978
21979    pub fn open_context_menu(
21980        &mut self,
21981        _: &OpenContextMenu,
21982        window: &mut Window,
21983        cx: &mut Context<Self>,
21984    ) {
21985        self.request_autoscroll(Autoscroll::newest(), cx);
21986        let position = self
21987            .selections
21988            .newest_display(&self.display_snapshot(cx))
21989            .start;
21990        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
21991    }
21992
21993    pub fn replay_insert_event(
21994        &mut self,
21995        text: &str,
21996        relative_utf16_range: Option<Range<isize>>,
21997        window: &mut Window,
21998        cx: &mut Context<Self>,
21999    ) {
22000        if !self.input_enabled {
22001            cx.emit(EditorEvent::InputIgnored { text: text.into() });
22002            return;
22003        }
22004        if let Some(relative_utf16_range) = relative_utf16_range {
22005            let selections = self
22006                .selections
22007                .all::<MultiBufferOffsetUtf16>(&self.display_snapshot(cx));
22008            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
22009                let new_ranges = selections.into_iter().map(|range| {
22010                    let start = MultiBufferOffsetUtf16(OffsetUtf16(
22011                        range
22012                            .head()
22013                            .0
22014                            .0
22015                            .saturating_add_signed(relative_utf16_range.start),
22016                    ));
22017                    let end = MultiBufferOffsetUtf16(OffsetUtf16(
22018                        range
22019                            .head()
22020                            .0
22021                            .0
22022                            .saturating_add_signed(relative_utf16_range.end),
22023                    ));
22024                    start..end
22025                });
22026                s.select_ranges(new_ranges);
22027            });
22028        }
22029
22030        self.handle_input(text, window, cx);
22031    }
22032
22033    pub fn is_focused(&self, window: &Window) -> bool {
22034        self.focus_handle.is_focused(window)
22035    }
22036
22037    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
22038        cx.emit(EditorEvent::Focused);
22039
22040        if let Some(descendant) = self
22041            .last_focused_descendant
22042            .take()
22043            .and_then(|descendant| descendant.upgrade())
22044        {
22045            window.focus(&descendant);
22046        } else {
22047            if let Some(blame) = self.blame.as_ref() {
22048                blame.update(cx, GitBlame::focus)
22049            }
22050
22051            self.blink_manager.update(cx, BlinkManager::enable);
22052            self.show_cursor_names(window, cx);
22053            self.buffer.update(cx, |buffer, cx| {
22054                buffer.finalize_last_transaction(cx);
22055                if self.leader_id.is_none() {
22056                    buffer.set_active_selections(
22057                        &self.selections.disjoint_anchors_arc(),
22058                        self.selections.line_mode(),
22059                        self.cursor_shape,
22060                        cx,
22061                    );
22062                }
22063            });
22064        }
22065    }
22066
22067    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
22068        cx.emit(EditorEvent::FocusedIn)
22069    }
22070
22071    fn handle_focus_out(
22072        &mut self,
22073        event: FocusOutEvent,
22074        _window: &mut Window,
22075        cx: &mut Context<Self>,
22076    ) {
22077        if event.blurred != self.focus_handle {
22078            self.last_focused_descendant = Some(event.blurred);
22079        }
22080        self.selection_drag_state = SelectionDragState::None;
22081        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
22082    }
22083
22084    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
22085        self.blink_manager.update(cx, BlinkManager::disable);
22086        self.buffer
22087            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
22088
22089        if let Some(blame) = self.blame.as_ref() {
22090            blame.update(cx, GitBlame::blur)
22091        }
22092        if !self.hover_state.focused(window, cx) {
22093            hide_hover(self, cx);
22094        }
22095        if !self
22096            .context_menu
22097            .borrow()
22098            .as_ref()
22099            .is_some_and(|context_menu| context_menu.focused(window, cx))
22100        {
22101            self.hide_context_menu(window, cx);
22102        }
22103        self.take_active_edit_prediction(cx);
22104        cx.emit(EditorEvent::Blurred);
22105        cx.notify();
22106    }
22107
22108    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
22109        let mut pending: String = window
22110            .pending_input_keystrokes()
22111            .into_iter()
22112            .flatten()
22113            .filter_map(|keystroke| {
22114                if keystroke.modifiers.is_subset_of(&Modifiers::shift()) {
22115                    keystroke.key_char.clone()
22116                } else {
22117                    None
22118                }
22119            })
22120            .collect();
22121
22122        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
22123            pending = "".to_string();
22124        }
22125
22126        let existing_pending = self
22127            .text_highlights::<PendingInput>(cx)
22128            .map(|(_, ranges)| ranges.to_vec());
22129        if existing_pending.is_none() && pending.is_empty() {
22130            return;
22131        }
22132        let transaction =
22133            self.transact(window, cx, |this, window, cx| {
22134                let selections = this
22135                    .selections
22136                    .all::<MultiBufferOffset>(&this.display_snapshot(cx));
22137                let edits = selections
22138                    .iter()
22139                    .map(|selection| (selection.end..selection.end, pending.clone()));
22140                this.edit(edits, cx);
22141                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
22142                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
22143                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
22144                    }));
22145                });
22146                if let Some(existing_ranges) = existing_pending {
22147                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
22148                    this.edit(edits, cx);
22149                }
22150            });
22151
22152        let snapshot = self.snapshot(window, cx);
22153        let ranges = self
22154            .selections
22155            .all::<MultiBufferOffset>(&snapshot.display_snapshot)
22156            .into_iter()
22157            .map(|selection| {
22158                snapshot.buffer_snapshot().anchor_after(selection.end)
22159                    ..snapshot
22160                        .buffer_snapshot()
22161                        .anchor_before(selection.end + pending.len())
22162            })
22163            .collect();
22164
22165        if pending.is_empty() {
22166            self.clear_highlights::<PendingInput>(cx);
22167        } else {
22168            self.highlight_text::<PendingInput>(
22169                ranges,
22170                HighlightStyle {
22171                    underline: Some(UnderlineStyle {
22172                        thickness: px(1.),
22173                        color: None,
22174                        wavy: false,
22175                    }),
22176                    ..Default::default()
22177                },
22178                cx,
22179            );
22180        }
22181
22182        self.ime_transaction = self.ime_transaction.or(transaction);
22183        if let Some(transaction) = self.ime_transaction {
22184            self.buffer.update(cx, |buffer, cx| {
22185                buffer.group_until_transaction(transaction, cx);
22186            });
22187        }
22188
22189        if self.text_highlights::<PendingInput>(cx).is_none() {
22190            self.ime_transaction.take();
22191        }
22192    }
22193
22194    pub fn register_action_renderer(
22195        &mut self,
22196        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
22197    ) -> Subscription {
22198        let id = self.next_editor_action_id.post_inc();
22199        self.editor_actions
22200            .borrow_mut()
22201            .insert(id, Box::new(listener));
22202
22203        let editor_actions = self.editor_actions.clone();
22204        Subscription::new(move || {
22205            editor_actions.borrow_mut().remove(&id);
22206        })
22207    }
22208
22209    pub fn register_action<A: Action>(
22210        &mut self,
22211        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
22212    ) -> Subscription {
22213        let id = self.next_editor_action_id.post_inc();
22214        let listener = Arc::new(listener);
22215        self.editor_actions.borrow_mut().insert(
22216            id,
22217            Box::new(move |_, window, _| {
22218                let listener = listener.clone();
22219                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
22220                    let action = action.downcast_ref().unwrap();
22221                    if phase == DispatchPhase::Bubble {
22222                        listener(action, window, cx)
22223                    }
22224                })
22225            }),
22226        );
22227
22228        let editor_actions = self.editor_actions.clone();
22229        Subscription::new(move || {
22230            editor_actions.borrow_mut().remove(&id);
22231        })
22232    }
22233
22234    pub fn file_header_size(&self) -> u32 {
22235        FILE_HEADER_HEIGHT
22236    }
22237
22238    pub fn restore(
22239        &mut self,
22240        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
22241        window: &mut Window,
22242        cx: &mut Context<Self>,
22243    ) {
22244        let workspace = self.workspace();
22245        let project = self.project();
22246        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
22247            let mut tasks = Vec::new();
22248            for (buffer_id, changes) in revert_changes {
22249                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
22250                    buffer.update(cx, |buffer, cx| {
22251                        buffer.edit(
22252                            changes
22253                                .into_iter()
22254                                .map(|(range, text)| (range, text.to_string())),
22255                            None,
22256                            cx,
22257                        );
22258                    });
22259
22260                    if let Some(project) =
22261                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
22262                    {
22263                        project.update(cx, |project, cx| {
22264                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
22265                        })
22266                    }
22267                }
22268            }
22269            tasks
22270        });
22271        cx.spawn_in(window, async move |_, cx| {
22272            for (buffer, task) in save_tasks {
22273                let result = task.await;
22274                if result.is_err() {
22275                    let Some(path) = buffer
22276                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
22277                        .ok()
22278                    else {
22279                        continue;
22280                    };
22281                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
22282                        let Some(task) = cx
22283                            .update_window_entity(workspace, |workspace, window, cx| {
22284                                workspace
22285                                    .open_path_preview(path, None, false, false, false, window, cx)
22286                            })
22287                            .ok()
22288                        else {
22289                            continue;
22290                        };
22291                        task.await.log_err();
22292                    }
22293                }
22294            }
22295        })
22296        .detach();
22297        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
22298            selections.refresh()
22299        });
22300    }
22301
22302    pub fn to_pixel_point(
22303        &self,
22304        source: multi_buffer::Anchor,
22305        editor_snapshot: &EditorSnapshot,
22306        window: &mut Window,
22307    ) -> Option<gpui::Point<Pixels>> {
22308        let source_point = source.to_display_point(editor_snapshot);
22309        self.display_to_pixel_point(source_point, editor_snapshot, window)
22310    }
22311
22312    pub fn display_to_pixel_point(
22313        &self,
22314        source: DisplayPoint,
22315        editor_snapshot: &EditorSnapshot,
22316        window: &mut Window,
22317    ) -> Option<gpui::Point<Pixels>> {
22318        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
22319        let text_layout_details = self.text_layout_details(window);
22320        let scroll_top = text_layout_details
22321            .scroll_anchor
22322            .scroll_position(editor_snapshot)
22323            .y;
22324
22325        if source.row().as_f64() < scroll_top.floor() {
22326            return None;
22327        }
22328        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
22329        let source_y = line_height * (source.row().as_f64() - scroll_top) as f32;
22330        Some(gpui::Point::new(source_x, source_y))
22331    }
22332
22333    pub fn has_visible_completions_menu(&self) -> bool {
22334        !self.edit_prediction_preview_is_active()
22335            && self.context_menu.borrow().as_ref().is_some_and(|menu| {
22336                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
22337            })
22338    }
22339
22340    pub fn register_addon<T: Addon>(&mut self, instance: T) {
22341        if self.mode.is_minimap() {
22342            return;
22343        }
22344        self.addons
22345            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
22346    }
22347
22348    pub fn unregister_addon<T: Addon>(&mut self) {
22349        self.addons.remove(&std::any::TypeId::of::<T>());
22350    }
22351
22352    pub fn addon<T: Addon>(&self) -> Option<&T> {
22353        let type_id = std::any::TypeId::of::<T>();
22354        self.addons
22355            .get(&type_id)
22356            .and_then(|item| item.to_any().downcast_ref::<T>())
22357    }
22358
22359    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
22360        let type_id = std::any::TypeId::of::<T>();
22361        self.addons
22362            .get_mut(&type_id)
22363            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
22364    }
22365
22366    fn character_dimensions(&self, window: &mut Window) -> CharacterDimensions {
22367        let text_layout_details = self.text_layout_details(window);
22368        let style = &text_layout_details.editor_style;
22369        let font_id = window.text_system().resolve_font(&style.text.font());
22370        let font_size = style.text.font_size.to_pixels(window.rem_size());
22371        let line_height = style.text.line_height_in_pixels(window.rem_size());
22372        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
22373        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
22374
22375        CharacterDimensions {
22376            em_width,
22377            em_advance,
22378            line_height,
22379        }
22380    }
22381
22382    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
22383        self.load_diff_task.clone()
22384    }
22385
22386    fn read_metadata_from_db(
22387        &mut self,
22388        item_id: u64,
22389        workspace_id: WorkspaceId,
22390        window: &mut Window,
22391        cx: &mut Context<Editor>,
22392    ) {
22393        if self.buffer_kind(cx) == ItemBufferKind::Singleton
22394            && !self.mode.is_minimap()
22395            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
22396        {
22397            let buffer_snapshot = OnceCell::new();
22398
22399            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err()
22400                && !folds.is_empty()
22401            {
22402                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
22403                self.fold_ranges(
22404                    folds
22405                        .into_iter()
22406                        .map(|(start, end)| {
22407                            snapshot.clip_offset(MultiBufferOffset(start), Bias::Left)
22408                                ..snapshot.clip_offset(MultiBufferOffset(end), Bias::Right)
22409                        })
22410                        .collect(),
22411                    false,
22412                    window,
22413                    cx,
22414                );
22415            }
22416
22417            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err()
22418                && !selections.is_empty()
22419            {
22420                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
22421                // skip adding the initial selection to selection history
22422                self.selection_history.mode = SelectionHistoryMode::Skipping;
22423                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
22424                    s.select_ranges(selections.into_iter().map(|(start, end)| {
22425                        snapshot.clip_offset(MultiBufferOffset(start), Bias::Left)
22426                            ..snapshot.clip_offset(MultiBufferOffset(end), Bias::Right)
22427                    }));
22428                });
22429                self.selection_history.mode = SelectionHistoryMode::Normal;
22430            };
22431        }
22432
22433        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
22434    }
22435
22436    fn update_lsp_data(
22437        &mut self,
22438        for_buffer: Option<BufferId>,
22439        window: &mut Window,
22440        cx: &mut Context<'_, Self>,
22441    ) {
22442        self.pull_diagnostics(for_buffer, window, cx);
22443        self.refresh_colors_for_visible_range(for_buffer, window, cx);
22444    }
22445
22446    fn register_visible_buffers(&mut self, cx: &mut Context<Self>) {
22447        if self.ignore_lsp_data() {
22448            return;
22449        }
22450        for (_, (visible_buffer, _, _)) in self.visible_excerpts(cx) {
22451            self.register_buffer(visible_buffer.read(cx).remote_id(), cx);
22452        }
22453    }
22454
22455    fn register_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
22456        if self.ignore_lsp_data() {
22457            return;
22458        }
22459
22460        if !self.registered_buffers.contains_key(&buffer_id)
22461            && let Some(project) = self.project.as_ref()
22462        {
22463            if let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) {
22464                project.update(cx, |project, cx| {
22465                    self.registered_buffers.insert(
22466                        buffer_id,
22467                        project.register_buffer_with_language_servers(&buffer, cx),
22468                    );
22469                });
22470            } else {
22471                self.registered_buffers.remove(&buffer_id);
22472            }
22473        }
22474    }
22475
22476    fn ignore_lsp_data(&self) -> bool {
22477        // `ActiveDiagnostic::All` is a special mode where editor's diagnostics are managed by the external view,
22478        // skip any LSP updates for it.
22479        self.active_diagnostics == ActiveDiagnostic::All || !self.mode().is_full()
22480    }
22481}
22482
22483fn edit_for_markdown_paste<'a>(
22484    buffer: &MultiBufferSnapshot,
22485    range: Range<MultiBufferOffset>,
22486    to_insert: &'a str,
22487    url: Option<url::Url>,
22488) -> (Range<MultiBufferOffset>, Cow<'a, str>) {
22489    if url.is_none() {
22490        return (range, Cow::Borrowed(to_insert));
22491    };
22492
22493    let old_text = buffer.text_for_range(range.clone()).collect::<String>();
22494
22495    let new_text = if range.is_empty() || url::Url::parse(&old_text).is_ok() {
22496        Cow::Borrowed(to_insert)
22497    } else {
22498        Cow::Owned(format!("[{old_text}]({to_insert})"))
22499    };
22500    (range, new_text)
22501}
22502
22503fn process_completion_for_edit(
22504    completion: &Completion,
22505    intent: CompletionIntent,
22506    buffer: &Entity<Buffer>,
22507    cursor_position: &text::Anchor,
22508    cx: &mut Context<Editor>,
22509) -> CompletionEdit {
22510    let buffer = buffer.read(cx);
22511    let buffer_snapshot = buffer.snapshot();
22512    let (snippet, new_text) = if completion.is_snippet() {
22513        let mut snippet_source = completion.new_text.clone();
22514        // Workaround for typescript language server issues so that methods don't expand within
22515        // strings and functions with type expressions. The previous point is used because the query
22516        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
22517        let previous_point = text::ToPoint::to_point(cursor_position, &buffer_snapshot);
22518        let previous_point = if previous_point.column > 0 {
22519            cursor_position.to_previous_offset(&buffer_snapshot)
22520        } else {
22521            cursor_position.to_offset(&buffer_snapshot)
22522        };
22523        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point)
22524            && scope.prefers_label_for_snippet_in_completion()
22525            && let Some(label) = completion.label()
22526            && matches!(
22527                completion.kind(),
22528                Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
22529            )
22530        {
22531            snippet_source = label;
22532        }
22533        match Snippet::parse(&snippet_source).log_err() {
22534            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
22535            None => (None, completion.new_text.clone()),
22536        }
22537    } else {
22538        (None, completion.new_text.clone())
22539    };
22540
22541    let mut range_to_replace = {
22542        let replace_range = &completion.replace_range;
22543        if let CompletionSource::Lsp {
22544            insert_range: Some(insert_range),
22545            ..
22546        } = &completion.source
22547        {
22548            debug_assert_eq!(
22549                insert_range.start, replace_range.start,
22550                "insert_range and replace_range should start at the same position"
22551            );
22552            debug_assert!(
22553                insert_range
22554                    .start
22555                    .cmp(cursor_position, &buffer_snapshot)
22556                    .is_le(),
22557                "insert_range should start before or at cursor position"
22558            );
22559            debug_assert!(
22560                replace_range
22561                    .start
22562                    .cmp(cursor_position, &buffer_snapshot)
22563                    .is_le(),
22564                "replace_range should start before or at cursor position"
22565            );
22566
22567            let should_replace = match intent {
22568                CompletionIntent::CompleteWithInsert => false,
22569                CompletionIntent::CompleteWithReplace => true,
22570                CompletionIntent::Complete | CompletionIntent::Compose => {
22571                    let insert_mode =
22572                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
22573                            .completions
22574                            .lsp_insert_mode;
22575                    match insert_mode {
22576                        LspInsertMode::Insert => false,
22577                        LspInsertMode::Replace => true,
22578                        LspInsertMode::ReplaceSubsequence => {
22579                            let mut text_to_replace = buffer.chars_for_range(
22580                                buffer.anchor_before(replace_range.start)
22581                                    ..buffer.anchor_after(replace_range.end),
22582                            );
22583                            let mut current_needle = text_to_replace.next();
22584                            for haystack_ch in completion.label.text.chars() {
22585                                if let Some(needle_ch) = current_needle
22586                                    && haystack_ch.eq_ignore_ascii_case(&needle_ch)
22587                                {
22588                                    current_needle = text_to_replace.next();
22589                                }
22590                            }
22591                            current_needle.is_none()
22592                        }
22593                        LspInsertMode::ReplaceSuffix => {
22594                            if replace_range
22595                                .end
22596                                .cmp(cursor_position, &buffer_snapshot)
22597                                .is_gt()
22598                            {
22599                                let range_after_cursor = *cursor_position..replace_range.end;
22600                                let text_after_cursor = buffer
22601                                    .text_for_range(
22602                                        buffer.anchor_before(range_after_cursor.start)
22603                                            ..buffer.anchor_after(range_after_cursor.end),
22604                                    )
22605                                    .collect::<String>()
22606                                    .to_ascii_lowercase();
22607                                completion
22608                                    .label
22609                                    .text
22610                                    .to_ascii_lowercase()
22611                                    .ends_with(&text_after_cursor)
22612                            } else {
22613                                true
22614                            }
22615                        }
22616                    }
22617                }
22618            };
22619
22620            if should_replace {
22621                replace_range.clone()
22622            } else {
22623                insert_range.clone()
22624            }
22625        } else {
22626            replace_range.clone()
22627        }
22628    };
22629
22630    if range_to_replace
22631        .end
22632        .cmp(cursor_position, &buffer_snapshot)
22633        .is_lt()
22634    {
22635        range_to_replace.end = *cursor_position;
22636    }
22637
22638    let replace_range = range_to_replace.to_offset(buffer);
22639    CompletionEdit {
22640        new_text,
22641        replace_range: BufferOffset(replace_range.start)..BufferOffset(replace_range.end),
22642        snippet,
22643    }
22644}
22645
22646struct CompletionEdit {
22647    new_text: String,
22648    replace_range: Range<BufferOffset>,
22649    snippet: Option<Snippet>,
22650}
22651
22652fn insert_extra_newline_brackets(
22653    buffer: &MultiBufferSnapshot,
22654    range: Range<MultiBufferOffset>,
22655    language: &language::LanguageScope,
22656) -> bool {
22657    let leading_whitespace_len = buffer
22658        .reversed_chars_at(range.start)
22659        .take_while(|c| c.is_whitespace() && *c != '\n')
22660        .map(|c| c.len_utf8())
22661        .sum::<usize>();
22662    let trailing_whitespace_len = buffer
22663        .chars_at(range.end)
22664        .take_while(|c| c.is_whitespace() && *c != '\n')
22665        .map(|c| c.len_utf8())
22666        .sum::<usize>();
22667    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
22668
22669    language.brackets().any(|(pair, enabled)| {
22670        let pair_start = pair.start.trim_end();
22671        let pair_end = pair.end.trim_start();
22672
22673        enabled
22674            && pair.newline
22675            && buffer.contains_str_at(range.end, pair_end)
22676            && buffer.contains_str_at(
22677                range.start.saturating_sub_usize(pair_start.len()),
22678                pair_start,
22679            )
22680    })
22681}
22682
22683fn insert_extra_newline_tree_sitter(
22684    buffer: &MultiBufferSnapshot,
22685    range: Range<MultiBufferOffset>,
22686) -> bool {
22687    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
22688        [(buffer, range, _)] => (*buffer, range.clone()),
22689        _ => return false,
22690    };
22691    let pair = {
22692        let mut result: Option<BracketMatch> = None;
22693
22694        for pair in buffer
22695            .all_bracket_ranges(range.start.0..range.end.0)
22696            .filter(move |pair| {
22697                pair.open_range.start <= range.start.0 && pair.close_range.end >= range.end.0
22698            })
22699        {
22700            let len = pair.close_range.end - pair.open_range.start;
22701
22702            if let Some(existing) = &result {
22703                let existing_len = existing.close_range.end - existing.open_range.start;
22704                if len > existing_len {
22705                    continue;
22706                }
22707            }
22708
22709            result = Some(pair);
22710        }
22711
22712        result
22713    };
22714    let Some(pair) = pair else {
22715        return false;
22716    };
22717    pair.newline_only
22718        && buffer
22719            .chars_for_range(pair.open_range.end..range.start.0)
22720            .chain(buffer.chars_for_range(range.end.0..pair.close_range.start))
22721            .all(|c| c.is_whitespace() && c != '\n')
22722}
22723
22724fn update_uncommitted_diff_for_buffer(
22725    editor: Entity<Editor>,
22726    project: &Entity<Project>,
22727    buffers: impl IntoIterator<Item = Entity<Buffer>>,
22728    buffer: Entity<MultiBuffer>,
22729    cx: &mut App,
22730) -> Task<()> {
22731    let mut tasks = Vec::new();
22732    project.update(cx, |project, cx| {
22733        for buffer in buffers {
22734            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
22735                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
22736            }
22737        }
22738    });
22739    cx.spawn(async move |cx| {
22740        let diffs = future::join_all(tasks).await;
22741        if editor
22742            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
22743            .unwrap_or(false)
22744        {
22745            return;
22746        }
22747
22748        buffer
22749            .update(cx, |buffer, cx| {
22750                for diff in diffs.into_iter().flatten() {
22751                    buffer.add_diff(diff, cx);
22752                }
22753            })
22754            .ok();
22755    })
22756}
22757
22758fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
22759    let tab_size = tab_size.get() as usize;
22760    let mut width = offset;
22761
22762    for ch in text.chars() {
22763        width += if ch == '\t' {
22764            tab_size - (width % tab_size)
22765        } else {
22766            1
22767        };
22768    }
22769
22770    width - offset
22771}
22772
22773#[cfg(test)]
22774mod tests {
22775    use super::*;
22776
22777    #[test]
22778    fn test_string_size_with_expanded_tabs() {
22779        let nz = |val| NonZeroU32::new(val).unwrap();
22780        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
22781        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
22782        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
22783        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
22784        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
22785        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
22786        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
22787        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
22788    }
22789}
22790
22791/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
22792struct WordBreakingTokenizer<'a> {
22793    input: &'a str,
22794}
22795
22796impl<'a> WordBreakingTokenizer<'a> {
22797    fn new(input: &'a str) -> Self {
22798        Self { input }
22799    }
22800}
22801
22802fn is_char_ideographic(ch: char) -> bool {
22803    use unicode_script::Script::*;
22804    use unicode_script::UnicodeScript;
22805    matches!(ch.script(), Han | Tangut | Yi)
22806}
22807
22808fn is_grapheme_ideographic(text: &str) -> bool {
22809    text.chars().any(is_char_ideographic)
22810}
22811
22812fn is_grapheme_whitespace(text: &str) -> bool {
22813    text.chars().any(|x| x.is_whitespace())
22814}
22815
22816fn should_stay_with_preceding_ideograph(text: &str) -> bool {
22817    text.chars()
22818        .next()
22819        .is_some_and(|ch| matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…'))
22820}
22821
22822#[derive(PartialEq, Eq, Debug, Clone, Copy)]
22823enum WordBreakToken<'a> {
22824    Word { token: &'a str, grapheme_len: usize },
22825    InlineWhitespace { token: &'a str, grapheme_len: usize },
22826    Newline,
22827}
22828
22829impl<'a> Iterator for WordBreakingTokenizer<'a> {
22830    /// Yields a span, the count of graphemes in the token, and whether it was
22831    /// whitespace. Note that it also breaks at word boundaries.
22832    type Item = WordBreakToken<'a>;
22833
22834    fn next(&mut self) -> Option<Self::Item> {
22835        use unicode_segmentation::UnicodeSegmentation;
22836        if self.input.is_empty() {
22837            return None;
22838        }
22839
22840        let mut iter = self.input.graphemes(true).peekable();
22841        let mut offset = 0;
22842        let mut grapheme_len = 0;
22843        if let Some(first_grapheme) = iter.next() {
22844            let is_newline = first_grapheme == "\n";
22845            let is_whitespace = is_grapheme_whitespace(first_grapheme);
22846            offset += first_grapheme.len();
22847            grapheme_len += 1;
22848            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
22849                if let Some(grapheme) = iter.peek().copied()
22850                    && should_stay_with_preceding_ideograph(grapheme)
22851                {
22852                    offset += grapheme.len();
22853                    grapheme_len += 1;
22854                }
22855            } else {
22856                let mut words = self.input[offset..].split_word_bound_indices().peekable();
22857                let mut next_word_bound = words.peek().copied();
22858                if next_word_bound.is_some_and(|(i, _)| i == 0) {
22859                    next_word_bound = words.next();
22860                }
22861                while let Some(grapheme) = iter.peek().copied() {
22862                    if next_word_bound.is_some_and(|(i, _)| i == offset) {
22863                        break;
22864                    };
22865                    if is_grapheme_whitespace(grapheme) != is_whitespace
22866                        || (grapheme == "\n") != is_newline
22867                    {
22868                        break;
22869                    };
22870                    offset += grapheme.len();
22871                    grapheme_len += 1;
22872                    iter.next();
22873                }
22874            }
22875            let token = &self.input[..offset];
22876            self.input = &self.input[offset..];
22877            if token == "\n" {
22878                Some(WordBreakToken::Newline)
22879            } else if is_whitespace {
22880                Some(WordBreakToken::InlineWhitespace {
22881                    token,
22882                    grapheme_len,
22883                })
22884            } else {
22885                Some(WordBreakToken::Word {
22886                    token,
22887                    grapheme_len,
22888                })
22889            }
22890        } else {
22891            None
22892        }
22893    }
22894}
22895
22896#[test]
22897fn test_word_breaking_tokenizer() {
22898    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
22899        ("", &[]),
22900        ("  ", &[whitespace("  ", 2)]),
22901        ("Ʒ", &[word("Ʒ", 1)]),
22902        ("Ǽ", &[word("Ǽ", 1)]),
22903        ("", &[word("", 1)]),
22904        ("⋑⋑", &[word("⋑⋑", 2)]),
22905        (
22906            "原理,进而",
22907            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
22908        ),
22909        (
22910            "hello world",
22911            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
22912        ),
22913        (
22914            "hello, world",
22915            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
22916        ),
22917        (
22918            "  hello world",
22919            &[
22920                whitespace("  ", 2),
22921                word("hello", 5),
22922                whitespace(" ", 1),
22923                word("world", 5),
22924            ],
22925        ),
22926        (
22927            "这是什么 \n 钢笔",
22928            &[
22929                word("", 1),
22930                word("", 1),
22931                word("", 1),
22932                word("", 1),
22933                whitespace(" ", 1),
22934                newline(),
22935                whitespace(" ", 1),
22936                word("", 1),
22937                word("", 1),
22938            ],
22939        ),
22940        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
22941    ];
22942
22943    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
22944        WordBreakToken::Word {
22945            token,
22946            grapheme_len,
22947        }
22948    }
22949
22950    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
22951        WordBreakToken::InlineWhitespace {
22952            token,
22953            grapheme_len,
22954        }
22955    }
22956
22957    fn newline() -> WordBreakToken<'static> {
22958        WordBreakToken::Newline
22959    }
22960
22961    for (input, result) in tests {
22962        assert_eq!(
22963            WordBreakingTokenizer::new(input)
22964                .collect::<Vec<_>>()
22965                .as_slice(),
22966            *result,
22967        );
22968    }
22969}
22970
22971fn wrap_with_prefix(
22972    first_line_prefix: String,
22973    subsequent_lines_prefix: String,
22974    unwrapped_text: String,
22975    wrap_column: usize,
22976    tab_size: NonZeroU32,
22977    preserve_existing_whitespace: bool,
22978) -> String {
22979    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
22980    let subsequent_lines_prefix_len =
22981        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
22982    let mut wrapped_text = String::new();
22983    let mut current_line = first_line_prefix;
22984    let mut is_first_line = true;
22985
22986    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
22987    let mut current_line_len = first_line_prefix_len;
22988    let mut in_whitespace = false;
22989    for token in tokenizer {
22990        let have_preceding_whitespace = in_whitespace;
22991        match token {
22992            WordBreakToken::Word {
22993                token,
22994                grapheme_len,
22995            } => {
22996                in_whitespace = false;
22997                let current_prefix_len = if is_first_line {
22998                    first_line_prefix_len
22999                } else {
23000                    subsequent_lines_prefix_len
23001                };
23002                if current_line_len + grapheme_len > wrap_column
23003                    && current_line_len != current_prefix_len
23004                {
23005                    wrapped_text.push_str(current_line.trim_end());
23006                    wrapped_text.push('\n');
23007                    is_first_line = false;
23008                    current_line = subsequent_lines_prefix.clone();
23009                    current_line_len = subsequent_lines_prefix_len;
23010                }
23011                current_line.push_str(token);
23012                current_line_len += grapheme_len;
23013            }
23014            WordBreakToken::InlineWhitespace {
23015                mut token,
23016                mut grapheme_len,
23017            } => {
23018                in_whitespace = true;
23019                if have_preceding_whitespace && !preserve_existing_whitespace {
23020                    continue;
23021                }
23022                if !preserve_existing_whitespace {
23023                    // Keep a single whitespace grapheme as-is
23024                    if let Some(first) =
23025                        unicode_segmentation::UnicodeSegmentation::graphemes(token, true).next()
23026                    {
23027                        token = first;
23028                    } else {
23029                        token = " ";
23030                    }
23031                    grapheme_len = 1;
23032                }
23033                let current_prefix_len = if is_first_line {
23034                    first_line_prefix_len
23035                } else {
23036                    subsequent_lines_prefix_len
23037                };
23038                if current_line_len + grapheme_len > wrap_column {
23039                    wrapped_text.push_str(current_line.trim_end());
23040                    wrapped_text.push('\n');
23041                    is_first_line = false;
23042                    current_line = subsequent_lines_prefix.clone();
23043                    current_line_len = subsequent_lines_prefix_len;
23044                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
23045                    current_line.push_str(token);
23046                    current_line_len += grapheme_len;
23047                }
23048            }
23049            WordBreakToken::Newline => {
23050                in_whitespace = true;
23051                let current_prefix_len = if is_first_line {
23052                    first_line_prefix_len
23053                } else {
23054                    subsequent_lines_prefix_len
23055                };
23056                if preserve_existing_whitespace {
23057                    wrapped_text.push_str(current_line.trim_end());
23058                    wrapped_text.push('\n');
23059                    is_first_line = false;
23060                    current_line = subsequent_lines_prefix.clone();
23061                    current_line_len = subsequent_lines_prefix_len;
23062                } else if have_preceding_whitespace {
23063                    continue;
23064                } else if current_line_len + 1 > wrap_column
23065                    && current_line_len != current_prefix_len
23066                {
23067                    wrapped_text.push_str(current_line.trim_end());
23068                    wrapped_text.push('\n');
23069                    is_first_line = false;
23070                    current_line = subsequent_lines_prefix.clone();
23071                    current_line_len = subsequent_lines_prefix_len;
23072                } else if current_line_len != current_prefix_len {
23073                    current_line.push(' ');
23074                    current_line_len += 1;
23075                }
23076            }
23077        }
23078    }
23079
23080    if !current_line.is_empty() {
23081        wrapped_text.push_str(&current_line);
23082    }
23083    wrapped_text
23084}
23085
23086#[test]
23087fn test_wrap_with_prefix() {
23088    assert_eq!(
23089        wrap_with_prefix(
23090            "# ".to_string(),
23091            "# ".to_string(),
23092            "abcdefg".to_string(),
23093            4,
23094            NonZeroU32::new(4).unwrap(),
23095            false,
23096        ),
23097        "# abcdefg"
23098    );
23099    assert_eq!(
23100        wrap_with_prefix(
23101            "".to_string(),
23102            "".to_string(),
23103            "\thello world".to_string(),
23104            8,
23105            NonZeroU32::new(4).unwrap(),
23106            false,
23107        ),
23108        "hello\nworld"
23109    );
23110    assert_eq!(
23111        wrap_with_prefix(
23112            "// ".to_string(),
23113            "// ".to_string(),
23114            "xx \nyy zz aa bb cc".to_string(),
23115            12,
23116            NonZeroU32::new(4).unwrap(),
23117            false,
23118        ),
23119        "// xx yy zz\n// aa bb cc"
23120    );
23121    assert_eq!(
23122        wrap_with_prefix(
23123            String::new(),
23124            String::new(),
23125            "这是什么 \n 钢笔".to_string(),
23126            3,
23127            NonZeroU32::new(4).unwrap(),
23128            false,
23129        ),
23130        "这是什\n么 钢\n"
23131    );
23132    assert_eq!(
23133        wrap_with_prefix(
23134            String::new(),
23135            String::new(),
23136            format!("foo{}bar", '\u{2009}'), // thin space
23137            80,
23138            NonZeroU32::new(4).unwrap(),
23139            false,
23140        ),
23141        format!("foo{}bar", '\u{2009}')
23142    );
23143}
23144
23145pub trait CollaborationHub {
23146    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
23147    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
23148    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
23149}
23150
23151impl CollaborationHub for Entity<Project> {
23152    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
23153        self.read(cx).collaborators()
23154    }
23155
23156    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
23157        self.read(cx).user_store().read(cx).participant_indices()
23158    }
23159
23160    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
23161        let this = self.read(cx);
23162        let user_ids = this.collaborators().values().map(|c| c.user_id);
23163        this.user_store().read(cx).participant_names(user_ids, cx)
23164    }
23165}
23166
23167pub trait SemanticsProvider {
23168    fn hover(
23169        &self,
23170        buffer: &Entity<Buffer>,
23171        position: text::Anchor,
23172        cx: &mut App,
23173    ) -> Option<Task<Option<Vec<project::Hover>>>>;
23174
23175    fn inline_values(
23176        &self,
23177        buffer_handle: Entity<Buffer>,
23178        range: Range<text::Anchor>,
23179        cx: &mut App,
23180    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
23181
23182    fn applicable_inlay_chunks(
23183        &self,
23184        buffer: &Entity<Buffer>,
23185        ranges: &[Range<text::Anchor>],
23186        cx: &mut App,
23187    ) -> Vec<Range<BufferRow>>;
23188
23189    fn invalidate_inlay_hints(&self, for_buffers: &HashSet<BufferId>, cx: &mut App);
23190
23191    fn inlay_hints(
23192        &self,
23193        invalidate: InvalidationStrategy,
23194        buffer: Entity<Buffer>,
23195        ranges: Vec<Range<text::Anchor>>,
23196        known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
23197        cx: &mut App,
23198    ) -> Option<HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>>>;
23199
23200    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
23201
23202    fn document_highlights(
23203        &self,
23204        buffer: &Entity<Buffer>,
23205        position: text::Anchor,
23206        cx: &mut App,
23207    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
23208
23209    fn definitions(
23210        &self,
23211        buffer: &Entity<Buffer>,
23212        position: text::Anchor,
23213        kind: GotoDefinitionKind,
23214        cx: &mut App,
23215    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>>;
23216
23217    fn range_for_rename(
23218        &self,
23219        buffer: &Entity<Buffer>,
23220        position: text::Anchor,
23221        cx: &mut App,
23222    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
23223
23224    fn perform_rename(
23225        &self,
23226        buffer: &Entity<Buffer>,
23227        position: text::Anchor,
23228        new_name: String,
23229        cx: &mut App,
23230    ) -> Option<Task<Result<ProjectTransaction>>>;
23231}
23232
23233pub trait CompletionProvider {
23234    fn completions(
23235        &self,
23236        excerpt_id: ExcerptId,
23237        buffer: &Entity<Buffer>,
23238        buffer_position: text::Anchor,
23239        trigger: CompletionContext,
23240        window: &mut Window,
23241        cx: &mut Context<Editor>,
23242    ) -> Task<Result<Vec<CompletionResponse>>>;
23243
23244    fn resolve_completions(
23245        &self,
23246        _buffer: Entity<Buffer>,
23247        _completion_indices: Vec<usize>,
23248        _completions: Rc<RefCell<Box<[Completion]>>>,
23249        _cx: &mut Context<Editor>,
23250    ) -> Task<Result<bool>> {
23251        Task::ready(Ok(false))
23252    }
23253
23254    fn apply_additional_edits_for_completion(
23255        &self,
23256        _buffer: Entity<Buffer>,
23257        _completions: Rc<RefCell<Box<[Completion]>>>,
23258        _completion_index: usize,
23259        _push_to_history: bool,
23260        _cx: &mut Context<Editor>,
23261    ) -> Task<Result<Option<language::Transaction>>> {
23262        Task::ready(Ok(None))
23263    }
23264
23265    fn is_completion_trigger(
23266        &self,
23267        buffer: &Entity<Buffer>,
23268        position: language::Anchor,
23269        text: &str,
23270        trigger_in_words: bool,
23271        menu_is_open: bool,
23272        cx: &mut Context<Editor>,
23273    ) -> bool;
23274
23275    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
23276
23277    fn sort_completions(&self) -> bool {
23278        true
23279    }
23280
23281    fn filter_completions(&self) -> bool {
23282        true
23283    }
23284
23285    fn show_snippets(&self) -> bool {
23286        false
23287    }
23288}
23289
23290pub trait CodeActionProvider {
23291    fn id(&self) -> Arc<str>;
23292
23293    fn code_actions(
23294        &self,
23295        buffer: &Entity<Buffer>,
23296        range: Range<text::Anchor>,
23297        window: &mut Window,
23298        cx: &mut App,
23299    ) -> Task<Result<Vec<CodeAction>>>;
23300
23301    fn apply_code_action(
23302        &self,
23303        buffer_handle: Entity<Buffer>,
23304        action: CodeAction,
23305        excerpt_id: ExcerptId,
23306        push_to_history: bool,
23307        window: &mut Window,
23308        cx: &mut App,
23309    ) -> Task<Result<ProjectTransaction>>;
23310}
23311
23312impl CodeActionProvider for Entity<Project> {
23313    fn id(&self) -> Arc<str> {
23314        "project".into()
23315    }
23316
23317    fn code_actions(
23318        &self,
23319        buffer: &Entity<Buffer>,
23320        range: Range<text::Anchor>,
23321        _window: &mut Window,
23322        cx: &mut App,
23323    ) -> Task<Result<Vec<CodeAction>>> {
23324        self.update(cx, |project, cx| {
23325            let code_lens_actions = project.code_lens_actions(buffer, range.clone(), cx);
23326            let code_actions = project.code_actions(buffer, range, None, cx);
23327            cx.background_spawn(async move {
23328                let (code_lens_actions, code_actions) = join(code_lens_actions, code_actions).await;
23329                Ok(code_lens_actions
23330                    .context("code lens fetch")?
23331                    .into_iter()
23332                    .flatten()
23333                    .chain(
23334                        code_actions
23335                            .context("code action fetch")?
23336                            .into_iter()
23337                            .flatten(),
23338                    )
23339                    .collect())
23340            })
23341        })
23342    }
23343
23344    fn apply_code_action(
23345        &self,
23346        buffer_handle: Entity<Buffer>,
23347        action: CodeAction,
23348        _excerpt_id: ExcerptId,
23349        push_to_history: bool,
23350        _window: &mut Window,
23351        cx: &mut App,
23352    ) -> Task<Result<ProjectTransaction>> {
23353        self.update(cx, |project, cx| {
23354            project.apply_code_action(buffer_handle, action, push_to_history, cx)
23355        })
23356    }
23357}
23358
23359fn snippet_completions(
23360    project: &Project,
23361    buffer: &Entity<Buffer>,
23362    buffer_anchor: text::Anchor,
23363    classifier: CharClassifier,
23364    cx: &mut App,
23365) -> Task<Result<CompletionResponse>> {
23366    let languages = buffer.read(cx).languages_at(buffer_anchor);
23367    let snippet_store = project.snippets().read(cx);
23368
23369    let scopes: Vec<_> = languages
23370        .iter()
23371        .filter_map(|language| {
23372            let language_name = language.lsp_id();
23373            let snippets = snippet_store.snippets_for(Some(language_name), cx);
23374
23375            if snippets.is_empty() {
23376                None
23377            } else {
23378                Some((language.default_scope(), snippets))
23379            }
23380        })
23381        .collect();
23382
23383    if scopes.is_empty() {
23384        return Task::ready(Ok(CompletionResponse {
23385            completions: vec![],
23386            display_options: CompletionDisplayOptions::default(),
23387            is_incomplete: false,
23388        }));
23389    }
23390
23391    let snapshot = buffer.read(cx).text_snapshot();
23392    let executor = cx.background_executor().clone();
23393
23394    cx.background_spawn(async move {
23395        let is_word_char = |c| classifier.is_word(c);
23396
23397        let mut is_incomplete = false;
23398        let mut completions: Vec<Completion> = Vec::new();
23399
23400        const MAX_PREFIX_LEN: usize = 128;
23401        let buffer_offset = text::ToOffset::to_offset(&buffer_anchor, &snapshot);
23402        let window_start = buffer_offset.saturating_sub(MAX_PREFIX_LEN);
23403        let window_start = snapshot.clip_offset(window_start, Bias::Left);
23404
23405        let max_buffer_window: String = snapshot
23406            .text_for_range(window_start..buffer_offset)
23407            .collect();
23408
23409        if max_buffer_window.is_empty() {
23410            return Ok(CompletionResponse {
23411                completions: vec![],
23412                display_options: CompletionDisplayOptions::default(),
23413                is_incomplete: true,
23414            });
23415        }
23416
23417        for (_scope, snippets) in scopes.into_iter() {
23418            // Sort snippets by word count to match longer snippet prefixes first.
23419            let mut sorted_snippet_candidates = snippets
23420                .iter()
23421                .enumerate()
23422                .flat_map(|(snippet_ix, snippet)| {
23423                    snippet
23424                        .prefix
23425                        .iter()
23426                        .enumerate()
23427                        .map(move |(prefix_ix, prefix)| {
23428                            let word_count =
23429                                snippet_candidate_suffixes(prefix, is_word_char).count();
23430                            ((snippet_ix, prefix_ix), prefix, word_count)
23431                        })
23432                })
23433                .collect_vec();
23434            sorted_snippet_candidates
23435                .sort_unstable_by_key(|(_, _, word_count)| Reverse(*word_count));
23436
23437            // Each prefix may be matched multiple times; the completion menu must filter out duplicates.
23438
23439            let buffer_windows = snippet_candidate_suffixes(&max_buffer_window, is_word_char)
23440                .take(
23441                    sorted_snippet_candidates
23442                        .first()
23443                        .map(|(_, _, word_count)| *word_count)
23444                        .unwrap_or_default(),
23445                )
23446                .collect_vec();
23447
23448            const MAX_RESULTS: usize = 100;
23449            // Each match also remembers how many characters from the buffer it consumed
23450            let mut matches: Vec<(StringMatch, usize)> = vec![];
23451
23452            let mut snippet_list_cutoff_index = 0;
23453            for (buffer_index, buffer_window) in buffer_windows.iter().enumerate().rev() {
23454                let word_count = buffer_index + 1;
23455                // Increase `snippet_list_cutoff_index` until we have all of the
23456                // snippets with sufficiently many words.
23457                while sorted_snippet_candidates
23458                    .get(snippet_list_cutoff_index)
23459                    .is_some_and(|(_ix, _prefix, snippet_word_count)| {
23460                        *snippet_word_count >= word_count
23461                    })
23462                {
23463                    snippet_list_cutoff_index += 1;
23464                }
23465
23466                // Take only the candidates with at least `word_count` many words
23467                let snippet_candidates_at_word_len =
23468                    &sorted_snippet_candidates[..snippet_list_cutoff_index];
23469
23470                let candidates = snippet_candidates_at_word_len
23471                    .iter()
23472                    .map(|(_snippet_ix, prefix, _snippet_word_count)| prefix)
23473                    .enumerate() // index in `sorted_snippet_candidates`
23474                    // First char must match
23475                    .filter(|(_ix, prefix)| {
23476                        itertools::equal(
23477                            prefix
23478                                .chars()
23479                                .next()
23480                                .into_iter()
23481                                .flat_map(|c| c.to_lowercase()),
23482                            buffer_window
23483                                .chars()
23484                                .next()
23485                                .into_iter()
23486                                .flat_map(|c| c.to_lowercase()),
23487                        )
23488                    })
23489                    .map(|(ix, prefix)| StringMatchCandidate::new(ix, prefix))
23490                    .collect::<Vec<StringMatchCandidate>>();
23491
23492                matches.extend(
23493                    fuzzy::match_strings(
23494                        &candidates,
23495                        &buffer_window,
23496                        buffer_window.chars().any(|c| c.is_uppercase()),
23497                        true,
23498                        MAX_RESULTS - matches.len(), // always prioritize longer snippets
23499                        &Default::default(),
23500                        executor.clone(),
23501                    )
23502                    .await
23503                    .into_iter()
23504                    .map(|string_match| (string_match, buffer_window.len())),
23505                );
23506
23507                if matches.len() >= MAX_RESULTS {
23508                    break;
23509                }
23510            }
23511
23512            let to_lsp = |point: &text::Anchor| {
23513                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
23514                point_to_lsp(end)
23515            };
23516            let lsp_end = to_lsp(&buffer_anchor);
23517
23518            if matches.len() >= MAX_RESULTS {
23519                is_incomplete = true;
23520            }
23521
23522            completions.extend(matches.iter().map(|(string_match, buffer_window_len)| {
23523                let ((snippet_index, prefix_index), matching_prefix, _snippet_word_count) =
23524                    sorted_snippet_candidates[string_match.candidate_id];
23525                let snippet = &snippets[snippet_index];
23526                let start = buffer_offset - buffer_window_len;
23527                let start = snapshot.anchor_before(start);
23528                let range = start..buffer_anchor;
23529                let lsp_start = to_lsp(&start);
23530                let lsp_range = lsp::Range {
23531                    start: lsp_start,
23532                    end: lsp_end,
23533                };
23534                Completion {
23535                    replace_range: range,
23536                    new_text: snippet.body.clone(),
23537                    source: CompletionSource::Lsp {
23538                        insert_range: None,
23539                        server_id: LanguageServerId(usize::MAX),
23540                        resolved: true,
23541                        lsp_completion: Box::new(lsp::CompletionItem {
23542                            label: snippet.prefix.first().unwrap().clone(),
23543                            kind: Some(CompletionItemKind::SNIPPET),
23544                            label_details: snippet.description.as_ref().map(|description| {
23545                                lsp::CompletionItemLabelDetails {
23546                                    detail: Some(description.clone()),
23547                                    description: None,
23548                                }
23549                            }),
23550                            insert_text_format: Some(InsertTextFormat::SNIPPET),
23551                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
23552                                lsp::InsertReplaceEdit {
23553                                    new_text: snippet.body.clone(),
23554                                    insert: lsp_range,
23555                                    replace: lsp_range,
23556                                },
23557                            )),
23558                            filter_text: Some(snippet.body.clone()),
23559                            sort_text: Some(char::MAX.to_string()),
23560                            ..lsp::CompletionItem::default()
23561                        }),
23562                        lsp_defaults: None,
23563                    },
23564                    label: CodeLabel {
23565                        text: matching_prefix.clone(),
23566                        runs: Vec::new(),
23567                        filter_range: 0..matching_prefix.len(),
23568                    },
23569                    icon_path: None,
23570                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
23571                        single_line: snippet.name.clone().into(),
23572                        plain_text: snippet
23573                            .description
23574                            .clone()
23575                            .map(|description| description.into()),
23576                    }),
23577                    insert_text_mode: None,
23578                    confirm: None,
23579                    match_start: Some(start),
23580                    snippet_deduplication_key: Some((snippet_index, prefix_index)),
23581                }
23582            }));
23583        }
23584
23585        Ok(CompletionResponse {
23586            completions,
23587            display_options: CompletionDisplayOptions::default(),
23588            is_incomplete,
23589        })
23590    })
23591}
23592
23593impl CompletionProvider for Entity<Project> {
23594    fn completions(
23595        &self,
23596        _excerpt_id: ExcerptId,
23597        buffer: &Entity<Buffer>,
23598        buffer_position: text::Anchor,
23599        options: CompletionContext,
23600        _window: &mut Window,
23601        cx: &mut Context<Editor>,
23602    ) -> Task<Result<Vec<CompletionResponse>>> {
23603        self.update(cx, |project, cx| {
23604            let task = project.completions(buffer, buffer_position, options, cx);
23605            cx.background_spawn(task)
23606        })
23607    }
23608
23609    fn resolve_completions(
23610        &self,
23611        buffer: Entity<Buffer>,
23612        completion_indices: Vec<usize>,
23613        completions: Rc<RefCell<Box<[Completion]>>>,
23614        cx: &mut Context<Editor>,
23615    ) -> Task<Result<bool>> {
23616        self.update(cx, |project, cx| {
23617            project.lsp_store().update(cx, |lsp_store, cx| {
23618                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
23619            })
23620        })
23621    }
23622
23623    fn apply_additional_edits_for_completion(
23624        &self,
23625        buffer: Entity<Buffer>,
23626        completions: Rc<RefCell<Box<[Completion]>>>,
23627        completion_index: usize,
23628        push_to_history: bool,
23629        cx: &mut Context<Editor>,
23630    ) -> Task<Result<Option<language::Transaction>>> {
23631        self.update(cx, |project, cx| {
23632            project.lsp_store().update(cx, |lsp_store, cx| {
23633                lsp_store.apply_additional_edits_for_completion(
23634                    buffer,
23635                    completions,
23636                    completion_index,
23637                    push_to_history,
23638                    cx,
23639                )
23640            })
23641        })
23642    }
23643
23644    fn is_completion_trigger(
23645        &self,
23646        buffer: &Entity<Buffer>,
23647        position: language::Anchor,
23648        text: &str,
23649        trigger_in_words: bool,
23650        menu_is_open: bool,
23651        cx: &mut Context<Editor>,
23652    ) -> bool {
23653        let mut chars = text.chars();
23654        let char = if let Some(char) = chars.next() {
23655            char
23656        } else {
23657            return false;
23658        };
23659        if chars.next().is_some() {
23660            return false;
23661        }
23662
23663        let buffer = buffer.read(cx);
23664        let snapshot = buffer.snapshot();
23665        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
23666            return false;
23667        }
23668        let classifier = snapshot
23669            .char_classifier_at(position)
23670            .scope_context(Some(CharScopeContext::Completion));
23671        if trigger_in_words && classifier.is_word(char) {
23672            return true;
23673        }
23674
23675        buffer.completion_triggers().contains(text)
23676    }
23677
23678    fn show_snippets(&self) -> bool {
23679        true
23680    }
23681}
23682
23683impl SemanticsProvider for Entity<Project> {
23684    fn hover(
23685        &self,
23686        buffer: &Entity<Buffer>,
23687        position: text::Anchor,
23688        cx: &mut App,
23689    ) -> Option<Task<Option<Vec<project::Hover>>>> {
23690        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
23691    }
23692
23693    fn document_highlights(
23694        &self,
23695        buffer: &Entity<Buffer>,
23696        position: text::Anchor,
23697        cx: &mut App,
23698    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
23699        Some(self.update(cx, |project, cx| {
23700            project.document_highlights(buffer, position, cx)
23701        }))
23702    }
23703
23704    fn definitions(
23705        &self,
23706        buffer: &Entity<Buffer>,
23707        position: text::Anchor,
23708        kind: GotoDefinitionKind,
23709        cx: &mut App,
23710    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>> {
23711        Some(self.update(cx, |project, cx| match kind {
23712            GotoDefinitionKind::Symbol => project.definitions(buffer, position, cx),
23713            GotoDefinitionKind::Declaration => project.declarations(buffer, position, cx),
23714            GotoDefinitionKind::Type => project.type_definitions(buffer, position, cx),
23715            GotoDefinitionKind::Implementation => project.implementations(buffer, position, cx),
23716        }))
23717    }
23718
23719    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
23720        self.update(cx, |project, cx| {
23721            if project
23722                .active_debug_session(cx)
23723                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
23724            {
23725                return true;
23726            }
23727
23728            buffer.update(cx, |buffer, cx| {
23729                project.any_language_server_supports_inlay_hints(buffer, cx)
23730            })
23731        })
23732    }
23733
23734    fn inline_values(
23735        &self,
23736        buffer_handle: Entity<Buffer>,
23737        range: Range<text::Anchor>,
23738        cx: &mut App,
23739    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
23740        self.update(cx, |project, cx| {
23741            let (session, active_stack_frame) = project.active_debug_session(cx)?;
23742
23743            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
23744        })
23745    }
23746
23747    fn applicable_inlay_chunks(
23748        &self,
23749        buffer: &Entity<Buffer>,
23750        ranges: &[Range<text::Anchor>],
23751        cx: &mut App,
23752    ) -> Vec<Range<BufferRow>> {
23753        self.read(cx).lsp_store().update(cx, |lsp_store, cx| {
23754            lsp_store.applicable_inlay_chunks(buffer, ranges, cx)
23755        })
23756    }
23757
23758    fn invalidate_inlay_hints(&self, for_buffers: &HashSet<BufferId>, cx: &mut App) {
23759        self.read(cx).lsp_store().update(cx, |lsp_store, _| {
23760            lsp_store.invalidate_inlay_hints(for_buffers)
23761        });
23762    }
23763
23764    fn inlay_hints(
23765        &self,
23766        invalidate: InvalidationStrategy,
23767        buffer: Entity<Buffer>,
23768        ranges: Vec<Range<text::Anchor>>,
23769        known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
23770        cx: &mut App,
23771    ) -> Option<HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>>> {
23772        Some(self.read(cx).lsp_store().update(cx, |lsp_store, cx| {
23773            lsp_store.inlay_hints(invalidate, buffer, ranges, known_chunks, cx)
23774        }))
23775    }
23776
23777    fn range_for_rename(
23778        &self,
23779        buffer: &Entity<Buffer>,
23780        position: text::Anchor,
23781        cx: &mut App,
23782    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
23783        Some(self.update(cx, |project, cx| {
23784            let buffer = buffer.clone();
23785            let task = project.prepare_rename(buffer.clone(), position, cx);
23786            cx.spawn(async move |_, cx| {
23787                Ok(match task.await? {
23788                    PrepareRenameResponse::Success(range) => Some(range),
23789                    PrepareRenameResponse::InvalidPosition => None,
23790                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
23791                        // Fallback on using TreeSitter info to determine identifier range
23792                        buffer.read_with(cx, |buffer, _| {
23793                            let snapshot = buffer.snapshot();
23794                            let (range, kind) = snapshot.surrounding_word(position, None);
23795                            if kind != Some(CharKind::Word) {
23796                                return None;
23797                            }
23798                            Some(
23799                                snapshot.anchor_before(range.start)
23800                                    ..snapshot.anchor_after(range.end),
23801                            )
23802                        })?
23803                    }
23804                })
23805            })
23806        }))
23807    }
23808
23809    fn perform_rename(
23810        &self,
23811        buffer: &Entity<Buffer>,
23812        position: text::Anchor,
23813        new_name: String,
23814        cx: &mut App,
23815    ) -> Option<Task<Result<ProjectTransaction>>> {
23816        Some(self.update(cx, |project, cx| {
23817            project.perform_rename(buffer.clone(), position, new_name, cx)
23818        }))
23819    }
23820}
23821
23822fn consume_contiguous_rows(
23823    contiguous_row_selections: &mut Vec<Selection<Point>>,
23824    selection: &Selection<Point>,
23825    display_map: &DisplaySnapshot,
23826    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
23827) -> (MultiBufferRow, MultiBufferRow) {
23828    contiguous_row_selections.push(selection.clone());
23829    let start_row = starting_row(selection, display_map);
23830    let mut end_row = ending_row(selection, display_map);
23831
23832    while let Some(next_selection) = selections.peek() {
23833        if next_selection.start.row <= end_row.0 {
23834            end_row = ending_row(next_selection, display_map);
23835            contiguous_row_selections.push(selections.next().unwrap().clone());
23836        } else {
23837            break;
23838        }
23839    }
23840    (start_row, end_row)
23841}
23842
23843fn starting_row(selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
23844    if selection.start.column > 0 {
23845        MultiBufferRow(display_map.prev_line_boundary(selection.start).0.row)
23846    } else {
23847        MultiBufferRow(selection.start.row)
23848    }
23849}
23850
23851fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
23852    if next_selection.end.column > 0 || next_selection.is_empty() {
23853        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
23854    } else {
23855        MultiBufferRow(next_selection.end.row)
23856    }
23857}
23858
23859impl EditorSnapshot {
23860    pub fn remote_selections_in_range<'a>(
23861        &'a self,
23862        range: &'a Range<Anchor>,
23863        collaboration_hub: &dyn CollaborationHub,
23864        cx: &'a App,
23865    ) -> impl 'a + Iterator<Item = RemoteSelection> {
23866        let participant_names = collaboration_hub.user_names(cx);
23867        let participant_indices = collaboration_hub.user_participant_indices(cx);
23868        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
23869        let collaborators_by_replica_id = collaborators_by_peer_id
23870            .values()
23871            .map(|collaborator| (collaborator.replica_id, collaborator))
23872            .collect::<HashMap<_, _>>();
23873        self.buffer_snapshot()
23874            .selections_in_range(range, false)
23875            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
23876                if replica_id == ReplicaId::AGENT {
23877                    Some(RemoteSelection {
23878                        replica_id,
23879                        selection,
23880                        cursor_shape,
23881                        line_mode,
23882                        collaborator_id: CollaboratorId::Agent,
23883                        user_name: Some("Agent".into()),
23884                        color: cx.theme().players().agent(),
23885                    })
23886                } else {
23887                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
23888                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
23889                    let user_name = participant_names.get(&collaborator.user_id).cloned();
23890                    Some(RemoteSelection {
23891                        replica_id,
23892                        selection,
23893                        cursor_shape,
23894                        line_mode,
23895                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
23896                        user_name,
23897                        color: if let Some(index) = participant_index {
23898                            cx.theme().players().color_for_participant(index.0)
23899                        } else {
23900                            cx.theme().players().absent()
23901                        },
23902                    })
23903                }
23904            })
23905    }
23906
23907    pub fn hunks_for_ranges(
23908        &self,
23909        ranges: impl IntoIterator<Item = Range<Point>>,
23910    ) -> Vec<MultiBufferDiffHunk> {
23911        let mut hunks = Vec::new();
23912        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
23913            HashMap::default();
23914        for query_range in ranges {
23915            let query_rows =
23916                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
23917            for hunk in self.buffer_snapshot().diff_hunks_in_range(
23918                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
23919            ) {
23920                // Include deleted hunks that are adjacent to the query range, because
23921                // otherwise they would be missed.
23922                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
23923                if hunk.status().is_deleted() {
23924                    intersects_range |= hunk.row_range.start == query_rows.end;
23925                    intersects_range |= hunk.row_range.end == query_rows.start;
23926                }
23927                if intersects_range {
23928                    if !processed_buffer_rows
23929                        .entry(hunk.buffer_id)
23930                        .or_default()
23931                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
23932                    {
23933                        continue;
23934                    }
23935                    hunks.push(hunk);
23936                }
23937            }
23938        }
23939
23940        hunks
23941    }
23942
23943    fn display_diff_hunks_for_rows<'a>(
23944        &'a self,
23945        display_rows: Range<DisplayRow>,
23946        folded_buffers: &'a HashSet<BufferId>,
23947    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
23948        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
23949        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
23950
23951        self.buffer_snapshot()
23952            .diff_hunks_in_range(buffer_start..buffer_end)
23953            .filter_map(|hunk| {
23954                if folded_buffers.contains(&hunk.buffer_id) {
23955                    return None;
23956                }
23957
23958                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
23959                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
23960
23961                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
23962                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
23963
23964                let display_hunk = if hunk_display_start.column() != 0 {
23965                    DisplayDiffHunk::Folded {
23966                        display_row: hunk_display_start.row(),
23967                    }
23968                } else {
23969                    let mut end_row = hunk_display_end.row();
23970                    if hunk_display_end.column() > 0 {
23971                        end_row.0 += 1;
23972                    }
23973                    let is_created_file = hunk.is_created_file();
23974                    DisplayDiffHunk::Unfolded {
23975                        status: hunk.status(),
23976                        diff_base_byte_range: hunk.diff_base_byte_range.start.0
23977                            ..hunk.diff_base_byte_range.end.0,
23978                        display_row_range: hunk_display_start.row()..end_row,
23979                        multi_buffer_range: Anchor::range_in_buffer(
23980                            hunk.excerpt_id,
23981                            hunk.buffer_id,
23982                            hunk.buffer_range,
23983                        ),
23984                        is_created_file,
23985                    }
23986                };
23987
23988                Some(display_hunk)
23989            })
23990    }
23991
23992    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
23993        self.display_snapshot
23994            .buffer_snapshot()
23995            .language_at(position)
23996    }
23997
23998    pub fn is_focused(&self) -> bool {
23999        self.is_focused
24000    }
24001
24002    pub fn placeholder_text(&self) -> Option<String> {
24003        self.placeholder_display_snapshot
24004            .as_ref()
24005            .map(|display_map| display_map.text())
24006    }
24007
24008    pub fn scroll_position(&self) -> gpui::Point<ScrollOffset> {
24009        self.scroll_anchor.scroll_position(&self.display_snapshot)
24010    }
24011
24012    fn gutter_dimensions(
24013        &self,
24014        font_id: FontId,
24015        font_size: Pixels,
24016        max_line_number_width: Pixels,
24017        cx: &App,
24018    ) -> Option<GutterDimensions> {
24019        if !self.show_gutter {
24020            return None;
24021        }
24022
24023        let ch_width = cx.text_system().ch_width(font_id, font_size).log_err()?;
24024        let ch_advance = cx.text_system().ch_advance(font_id, font_size).log_err()?;
24025
24026        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
24027            matches!(
24028                ProjectSettings::get_global(cx).git.git_gutter,
24029                GitGutterSetting::TrackedFiles
24030            )
24031        });
24032        let gutter_settings = EditorSettings::get_global(cx).gutter;
24033        let show_line_numbers = self
24034            .show_line_numbers
24035            .unwrap_or(gutter_settings.line_numbers);
24036        let line_gutter_width = if show_line_numbers {
24037            // Avoid flicker-like gutter resizes when the line number gains another digit by
24038            // only resizing the gutter on files with > 10**min_line_number_digits lines.
24039            let min_width_for_number_on_gutter =
24040                ch_advance * gutter_settings.min_line_number_digits as f32;
24041            max_line_number_width.max(min_width_for_number_on_gutter)
24042        } else {
24043            0.0.into()
24044        };
24045
24046        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
24047        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
24048
24049        let git_blame_entries_width =
24050            self.git_blame_gutter_max_author_length
24051                .map(|max_author_length| {
24052                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
24053                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
24054
24055                    /// The number of characters to dedicate to gaps and margins.
24056                    const SPACING_WIDTH: usize = 4;
24057
24058                    let max_char_count = max_author_length.min(renderer.max_author_length())
24059                        + ::git::SHORT_SHA_LENGTH
24060                        + MAX_RELATIVE_TIMESTAMP.len()
24061                        + SPACING_WIDTH;
24062
24063                    ch_advance * max_char_count
24064                });
24065
24066        let is_singleton = self.buffer_snapshot().is_singleton();
24067
24068        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
24069        left_padding += if !is_singleton {
24070            ch_width * 4.0
24071        } else if show_runnables || show_breakpoints {
24072            ch_width * 3.0
24073        } else if show_git_gutter && show_line_numbers {
24074            ch_width * 2.0
24075        } else if show_git_gutter || show_line_numbers {
24076            ch_width
24077        } else {
24078            px(0.)
24079        };
24080
24081        let shows_folds = is_singleton && gutter_settings.folds;
24082
24083        let right_padding = if shows_folds && show_line_numbers {
24084            ch_width * 4.0
24085        } else if shows_folds || (!is_singleton && show_line_numbers) {
24086            ch_width * 3.0
24087        } else if show_line_numbers {
24088            ch_width
24089        } else {
24090            px(0.)
24091        };
24092
24093        Some(GutterDimensions {
24094            left_padding,
24095            right_padding,
24096            width: line_gutter_width + left_padding + right_padding,
24097            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
24098            git_blame_entries_width,
24099        })
24100    }
24101
24102    pub fn render_crease_toggle(
24103        &self,
24104        buffer_row: MultiBufferRow,
24105        row_contains_cursor: bool,
24106        editor: Entity<Editor>,
24107        window: &mut Window,
24108        cx: &mut App,
24109    ) -> Option<AnyElement> {
24110        let folded = self.is_line_folded(buffer_row);
24111        let mut is_foldable = false;
24112
24113        if let Some(crease) = self
24114            .crease_snapshot
24115            .query_row(buffer_row, self.buffer_snapshot())
24116        {
24117            is_foldable = true;
24118            match crease {
24119                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
24120                    if let Some(render_toggle) = render_toggle {
24121                        let toggle_callback =
24122                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
24123                                if folded {
24124                                    editor.update(cx, |editor, cx| {
24125                                        editor.fold_at(buffer_row, window, cx)
24126                                    });
24127                                } else {
24128                                    editor.update(cx, |editor, cx| {
24129                                        editor.unfold_at(buffer_row, window, cx)
24130                                    });
24131                                }
24132                            });
24133                        return Some((render_toggle)(
24134                            buffer_row,
24135                            folded,
24136                            toggle_callback,
24137                            window,
24138                            cx,
24139                        ));
24140                    }
24141                }
24142            }
24143        }
24144
24145        is_foldable |= self.starts_indent(buffer_row);
24146
24147        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
24148            Some(
24149                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
24150                    .toggle_state(folded)
24151                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
24152                        if folded {
24153                            this.unfold_at(buffer_row, window, cx);
24154                        } else {
24155                            this.fold_at(buffer_row, window, cx);
24156                        }
24157                    }))
24158                    .into_any_element(),
24159            )
24160        } else {
24161            None
24162        }
24163    }
24164
24165    pub fn render_crease_trailer(
24166        &self,
24167        buffer_row: MultiBufferRow,
24168        window: &mut Window,
24169        cx: &mut App,
24170    ) -> Option<AnyElement> {
24171        let folded = self.is_line_folded(buffer_row);
24172        if let Crease::Inline { render_trailer, .. } = self
24173            .crease_snapshot
24174            .query_row(buffer_row, self.buffer_snapshot())?
24175        {
24176            let render_trailer = render_trailer.as_ref()?;
24177            Some(render_trailer(buffer_row, folded, window, cx))
24178        } else {
24179            None
24180        }
24181    }
24182}
24183
24184impl Deref for EditorSnapshot {
24185    type Target = DisplaySnapshot;
24186
24187    fn deref(&self) -> &Self::Target {
24188        &self.display_snapshot
24189    }
24190}
24191
24192#[derive(Clone, Debug, PartialEq, Eq)]
24193pub enum EditorEvent {
24194    InputIgnored {
24195        text: Arc<str>,
24196    },
24197    InputHandled {
24198        utf16_range_to_replace: Option<Range<isize>>,
24199        text: Arc<str>,
24200    },
24201    ExcerptsAdded {
24202        buffer: Entity<Buffer>,
24203        predecessor: ExcerptId,
24204        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
24205    },
24206    ExcerptsRemoved {
24207        ids: Vec<ExcerptId>,
24208        removed_buffer_ids: Vec<BufferId>,
24209    },
24210    BufferFoldToggled {
24211        ids: Vec<ExcerptId>,
24212        folded: bool,
24213    },
24214    ExcerptsEdited {
24215        ids: Vec<ExcerptId>,
24216    },
24217    ExcerptsExpanded {
24218        ids: Vec<ExcerptId>,
24219    },
24220    BufferEdited,
24221    Edited {
24222        transaction_id: clock::Lamport,
24223    },
24224    Reparsed(BufferId),
24225    Focused,
24226    FocusedIn,
24227    Blurred,
24228    DirtyChanged,
24229    Saved,
24230    TitleChanged,
24231    SelectionsChanged {
24232        local: bool,
24233    },
24234    ScrollPositionChanged {
24235        local: bool,
24236        autoscroll: bool,
24237    },
24238    TransactionUndone {
24239        transaction_id: clock::Lamport,
24240    },
24241    TransactionBegun {
24242        transaction_id: clock::Lamport,
24243    },
24244    CursorShapeChanged,
24245    BreadcrumbsChanged,
24246    PushedToNavHistory {
24247        anchor: Anchor,
24248        is_deactivate: bool,
24249    },
24250}
24251
24252impl EventEmitter<EditorEvent> for Editor {}
24253
24254impl Focusable for Editor {
24255    fn focus_handle(&self, _cx: &App) -> FocusHandle {
24256        self.focus_handle.clone()
24257    }
24258}
24259
24260impl Render for Editor {
24261    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
24262        let settings = ThemeSettings::get_global(cx);
24263
24264        let mut text_style = match self.mode {
24265            EditorMode::SingleLine | EditorMode::AutoHeight { .. } => TextStyle {
24266                color: cx.theme().colors().editor_foreground,
24267                font_family: settings.ui_font.family.clone(),
24268                font_features: settings.ui_font.features.clone(),
24269                font_fallbacks: settings.ui_font.fallbacks.clone(),
24270                font_size: rems(0.875).into(),
24271                font_weight: settings.ui_font.weight,
24272                line_height: relative(settings.buffer_line_height.value()),
24273                ..Default::default()
24274            },
24275            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
24276                color: cx.theme().colors().editor_foreground,
24277                font_family: settings.buffer_font.family.clone(),
24278                font_features: settings.buffer_font.features.clone(),
24279                font_fallbacks: settings.buffer_font.fallbacks.clone(),
24280                font_size: settings.buffer_font_size(cx).into(),
24281                font_weight: settings.buffer_font.weight,
24282                line_height: relative(settings.buffer_line_height.value()),
24283                ..Default::default()
24284            },
24285        };
24286        if let Some(text_style_refinement) = &self.text_style_refinement {
24287            text_style.refine(text_style_refinement)
24288        }
24289
24290        let background = match self.mode {
24291            EditorMode::SingleLine => cx.theme().system().transparent,
24292            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
24293            EditorMode::Full { .. } => cx.theme().colors().editor_background,
24294            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
24295        };
24296
24297        EditorElement::new(
24298            &cx.entity(),
24299            EditorStyle {
24300                background,
24301                border: cx.theme().colors().border,
24302                local_player: cx.theme().players().local(),
24303                text: text_style,
24304                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
24305                syntax: cx.theme().syntax().clone(),
24306                status: cx.theme().status().clone(),
24307                inlay_hints_style: make_inlay_hints_style(cx),
24308                edit_prediction_styles: make_suggestion_styles(cx),
24309                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
24310                show_underlines: self.diagnostics_enabled(),
24311            },
24312        )
24313    }
24314}
24315
24316impl EntityInputHandler for Editor {
24317    fn text_for_range(
24318        &mut self,
24319        range_utf16: Range<usize>,
24320        adjusted_range: &mut Option<Range<usize>>,
24321        _: &mut Window,
24322        cx: &mut Context<Self>,
24323    ) -> Option<String> {
24324        let snapshot = self.buffer.read(cx).read(cx);
24325        let start = snapshot.clip_offset_utf16(
24326            MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start)),
24327            Bias::Left,
24328        );
24329        let end = snapshot.clip_offset_utf16(
24330            MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.end)),
24331            Bias::Right,
24332        );
24333        if (start.0.0..end.0.0) != range_utf16 {
24334            adjusted_range.replace(start.0.0..end.0.0);
24335        }
24336        Some(snapshot.text_for_range(start..end).collect())
24337    }
24338
24339    fn selected_text_range(
24340        &mut self,
24341        ignore_disabled_input: bool,
24342        _: &mut Window,
24343        cx: &mut Context<Self>,
24344    ) -> Option<UTF16Selection> {
24345        // Prevent the IME menu from appearing when holding down an alphabetic key
24346        // while input is disabled.
24347        if !ignore_disabled_input && !self.input_enabled {
24348            return None;
24349        }
24350
24351        let selection = self
24352            .selections
24353            .newest::<MultiBufferOffsetUtf16>(&self.display_snapshot(cx));
24354        let range = selection.range();
24355
24356        Some(UTF16Selection {
24357            range: range.start.0.0..range.end.0.0,
24358            reversed: selection.reversed,
24359        })
24360    }
24361
24362    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
24363        let snapshot = self.buffer.read(cx).read(cx);
24364        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
24365        Some(range.start.to_offset_utf16(&snapshot).0.0..range.end.to_offset_utf16(&snapshot).0.0)
24366    }
24367
24368    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
24369        self.clear_highlights::<InputComposition>(cx);
24370        self.ime_transaction.take();
24371    }
24372
24373    fn replace_text_in_range(
24374        &mut self,
24375        range_utf16: Option<Range<usize>>,
24376        text: &str,
24377        window: &mut Window,
24378        cx: &mut Context<Self>,
24379    ) {
24380        if !self.input_enabled {
24381            cx.emit(EditorEvent::InputIgnored { text: text.into() });
24382            return;
24383        }
24384
24385        self.transact(window, cx, |this, window, cx| {
24386            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
24387                let range_utf16 = MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start))
24388                    ..MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.end));
24389                Some(this.selection_replacement_ranges(range_utf16, cx))
24390            } else {
24391                this.marked_text_ranges(cx)
24392            };
24393
24394            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
24395                let newest_selection_id = this.selections.newest_anchor().id;
24396                this.selections
24397                    .all::<MultiBufferOffsetUtf16>(&this.display_snapshot(cx))
24398                    .iter()
24399                    .zip(ranges_to_replace.iter())
24400                    .find_map(|(selection, range)| {
24401                        if selection.id == newest_selection_id {
24402                            Some(
24403                                (range.start.0.0 as isize - selection.head().0.0 as isize)
24404                                    ..(range.end.0.0 as isize - selection.head().0.0 as isize),
24405                            )
24406                        } else {
24407                            None
24408                        }
24409                    })
24410            });
24411
24412            cx.emit(EditorEvent::InputHandled {
24413                utf16_range_to_replace: range_to_replace,
24414                text: text.into(),
24415            });
24416
24417            if let Some(new_selected_ranges) = new_selected_ranges {
24418                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
24419                    selections.select_ranges(new_selected_ranges)
24420                });
24421                this.backspace(&Default::default(), window, cx);
24422            }
24423
24424            this.handle_input(text, window, cx);
24425        });
24426
24427        if let Some(transaction) = self.ime_transaction {
24428            self.buffer.update(cx, |buffer, cx| {
24429                buffer.group_until_transaction(transaction, cx);
24430            });
24431        }
24432
24433        self.unmark_text(window, cx);
24434    }
24435
24436    fn replace_and_mark_text_in_range(
24437        &mut self,
24438        range_utf16: Option<Range<usize>>,
24439        text: &str,
24440        new_selected_range_utf16: Option<Range<usize>>,
24441        window: &mut Window,
24442        cx: &mut Context<Self>,
24443    ) {
24444        if !self.input_enabled {
24445            return;
24446        }
24447
24448        let transaction = self.transact(window, cx, |this, window, cx| {
24449            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
24450                let snapshot = this.buffer.read(cx).read(cx);
24451                if let Some(relative_range_utf16) = range_utf16.as_ref() {
24452                    for marked_range in &mut marked_ranges {
24453                        marked_range.end = marked_range.start + relative_range_utf16.end;
24454                        marked_range.start += relative_range_utf16.start;
24455                        marked_range.start =
24456                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
24457                        marked_range.end =
24458                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
24459                    }
24460                }
24461                Some(marked_ranges)
24462            } else if let Some(range_utf16) = range_utf16 {
24463                let range_utf16 = MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start))
24464                    ..MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.end));
24465                Some(this.selection_replacement_ranges(range_utf16, cx))
24466            } else {
24467                None
24468            };
24469
24470            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
24471                let newest_selection_id = this.selections.newest_anchor().id;
24472                this.selections
24473                    .all::<MultiBufferOffsetUtf16>(&this.display_snapshot(cx))
24474                    .iter()
24475                    .zip(ranges_to_replace.iter())
24476                    .find_map(|(selection, range)| {
24477                        if selection.id == newest_selection_id {
24478                            Some(
24479                                (range.start.0.0 as isize - selection.head().0.0 as isize)
24480                                    ..(range.end.0.0 as isize - selection.head().0.0 as isize),
24481                            )
24482                        } else {
24483                            None
24484                        }
24485                    })
24486            });
24487
24488            cx.emit(EditorEvent::InputHandled {
24489                utf16_range_to_replace: range_to_replace,
24490                text: text.into(),
24491            });
24492
24493            if let Some(ranges) = ranges_to_replace {
24494                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
24495                    s.select_ranges(ranges)
24496                });
24497            }
24498
24499            let marked_ranges = {
24500                let snapshot = this.buffer.read(cx).read(cx);
24501                this.selections
24502                    .disjoint_anchors_arc()
24503                    .iter()
24504                    .map(|selection| {
24505                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
24506                    })
24507                    .collect::<Vec<_>>()
24508            };
24509
24510            if text.is_empty() {
24511                this.unmark_text(window, cx);
24512            } else {
24513                this.highlight_text::<InputComposition>(
24514                    marked_ranges.clone(),
24515                    HighlightStyle {
24516                        underline: Some(UnderlineStyle {
24517                            thickness: px(1.),
24518                            color: None,
24519                            wavy: false,
24520                        }),
24521                        ..Default::default()
24522                    },
24523                    cx,
24524                );
24525            }
24526
24527            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
24528            let use_autoclose = this.use_autoclose;
24529            let use_auto_surround = this.use_auto_surround;
24530            this.set_use_autoclose(false);
24531            this.set_use_auto_surround(false);
24532            this.handle_input(text, window, cx);
24533            this.set_use_autoclose(use_autoclose);
24534            this.set_use_auto_surround(use_auto_surround);
24535
24536            if let Some(new_selected_range) = new_selected_range_utf16 {
24537                let snapshot = this.buffer.read(cx).read(cx);
24538                let new_selected_ranges = marked_ranges
24539                    .into_iter()
24540                    .map(|marked_range| {
24541                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
24542                        let new_start = MultiBufferOffsetUtf16(OffsetUtf16(
24543                            insertion_start.0 + new_selected_range.start,
24544                        ));
24545                        let new_end = MultiBufferOffsetUtf16(OffsetUtf16(
24546                            insertion_start.0 + new_selected_range.end,
24547                        ));
24548                        snapshot.clip_offset_utf16(new_start, Bias::Left)
24549                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
24550                    })
24551                    .collect::<Vec<_>>();
24552
24553                drop(snapshot);
24554                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
24555                    selections.select_ranges(new_selected_ranges)
24556                });
24557            }
24558        });
24559
24560        self.ime_transaction = self.ime_transaction.or(transaction);
24561        if let Some(transaction) = self.ime_transaction {
24562            self.buffer.update(cx, |buffer, cx| {
24563                buffer.group_until_transaction(transaction, cx);
24564            });
24565        }
24566
24567        if self.text_highlights::<InputComposition>(cx).is_none() {
24568            self.ime_transaction.take();
24569        }
24570    }
24571
24572    fn bounds_for_range(
24573        &mut self,
24574        range_utf16: Range<usize>,
24575        element_bounds: gpui::Bounds<Pixels>,
24576        window: &mut Window,
24577        cx: &mut Context<Self>,
24578    ) -> Option<gpui::Bounds<Pixels>> {
24579        let text_layout_details = self.text_layout_details(window);
24580        let CharacterDimensions {
24581            em_width,
24582            em_advance,
24583            line_height,
24584        } = self.character_dimensions(window);
24585
24586        let snapshot = self.snapshot(window, cx);
24587        let scroll_position = snapshot.scroll_position();
24588        let scroll_left = scroll_position.x * ScrollOffset::from(em_advance);
24589
24590        let start =
24591            MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start)).to_display_point(&snapshot);
24592        let x = Pixels::from(
24593            ScrollOffset::from(
24594                snapshot.x_for_display_point(start, &text_layout_details)
24595                    + self.gutter_dimensions.full_width(),
24596            ) - scroll_left,
24597        );
24598        let y = line_height * (start.row().as_f64() - scroll_position.y) as f32;
24599
24600        Some(Bounds {
24601            origin: element_bounds.origin + point(x, y),
24602            size: size(em_width, line_height),
24603        })
24604    }
24605
24606    fn character_index_for_point(
24607        &mut self,
24608        point: gpui::Point<Pixels>,
24609        _window: &mut Window,
24610        _cx: &mut Context<Self>,
24611    ) -> Option<usize> {
24612        let position_map = self.last_position_map.as_ref()?;
24613        if !position_map.text_hitbox.contains(&point) {
24614            return None;
24615        }
24616        let display_point = position_map.point_for_position(point).previous_valid;
24617        let anchor = position_map
24618            .snapshot
24619            .display_point_to_anchor(display_point, Bias::Left);
24620        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot());
24621        Some(utf16_offset.0.0)
24622    }
24623
24624    fn accepts_text_input(&self, _window: &mut Window, _cx: &mut Context<Self>) -> bool {
24625        self.input_enabled
24626    }
24627}
24628
24629trait SelectionExt {
24630    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
24631    fn spanned_rows(
24632        &self,
24633        include_end_if_at_line_start: bool,
24634        map: &DisplaySnapshot,
24635    ) -> Range<MultiBufferRow>;
24636}
24637
24638impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
24639    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
24640        let start = self
24641            .start
24642            .to_point(map.buffer_snapshot())
24643            .to_display_point(map);
24644        let end = self
24645            .end
24646            .to_point(map.buffer_snapshot())
24647            .to_display_point(map);
24648        if self.reversed {
24649            end..start
24650        } else {
24651            start..end
24652        }
24653    }
24654
24655    fn spanned_rows(
24656        &self,
24657        include_end_if_at_line_start: bool,
24658        map: &DisplaySnapshot,
24659    ) -> Range<MultiBufferRow> {
24660        let start = self.start.to_point(map.buffer_snapshot());
24661        let mut end = self.end.to_point(map.buffer_snapshot());
24662        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
24663            end.row -= 1;
24664        }
24665
24666        let buffer_start = map.prev_line_boundary(start).0;
24667        let buffer_end = map.next_line_boundary(end).0;
24668        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
24669    }
24670}
24671
24672impl<T: InvalidationRegion> InvalidationStack<T> {
24673    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
24674    where
24675        S: Clone + ToOffset,
24676    {
24677        while let Some(region) = self.last() {
24678            let all_selections_inside_invalidation_ranges =
24679                if selections.len() == region.ranges().len() {
24680                    selections
24681                        .iter()
24682                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
24683                        .all(|(selection, invalidation_range)| {
24684                            let head = selection.head().to_offset(buffer);
24685                            invalidation_range.start <= head && invalidation_range.end >= head
24686                        })
24687                } else {
24688                    false
24689                };
24690
24691            if all_selections_inside_invalidation_ranges {
24692                break;
24693            } else {
24694                self.pop();
24695            }
24696        }
24697    }
24698}
24699
24700impl<T> Default for InvalidationStack<T> {
24701    fn default() -> Self {
24702        Self(Default::default())
24703    }
24704}
24705
24706impl<T> Deref for InvalidationStack<T> {
24707    type Target = Vec<T>;
24708
24709    fn deref(&self) -> &Self::Target {
24710        &self.0
24711    }
24712}
24713
24714impl<T> DerefMut for InvalidationStack<T> {
24715    fn deref_mut(&mut self) -> &mut Self::Target {
24716        &mut self.0
24717    }
24718}
24719
24720impl InvalidationRegion for SnippetState {
24721    fn ranges(&self) -> &[Range<Anchor>] {
24722        &self.ranges[self.active_index]
24723    }
24724}
24725
24726fn edit_prediction_edit_text(
24727    current_snapshot: &BufferSnapshot,
24728    edits: &[(Range<Anchor>, impl AsRef<str>)],
24729    edit_preview: &EditPreview,
24730    include_deletions: bool,
24731    cx: &App,
24732) -> HighlightedText {
24733    let edits = edits
24734        .iter()
24735        .map(|(anchor, text)| (anchor.start.text_anchor..anchor.end.text_anchor, text))
24736        .collect::<Vec<_>>();
24737
24738    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
24739}
24740
24741fn edit_prediction_fallback_text(edits: &[(Range<Anchor>, Arc<str>)], cx: &App) -> HighlightedText {
24742    // Fallback for providers that don't provide edit_preview (like Copilot/Supermaven)
24743    // Just show the raw edit text with basic styling
24744    let mut text = String::new();
24745    let mut highlights = Vec::new();
24746
24747    let insertion_highlight_style = HighlightStyle {
24748        color: Some(cx.theme().colors().text),
24749        ..Default::default()
24750    };
24751
24752    for (_, edit_text) in edits {
24753        let start_offset = text.len();
24754        text.push_str(edit_text);
24755        let end_offset = text.len();
24756
24757        if start_offset < end_offset {
24758            highlights.push((start_offset..end_offset, insertion_highlight_style));
24759        }
24760    }
24761
24762    HighlightedText {
24763        text: text.into(),
24764        highlights,
24765    }
24766}
24767
24768pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
24769    match severity {
24770        lsp::DiagnosticSeverity::ERROR => colors.error,
24771        lsp::DiagnosticSeverity::WARNING => colors.warning,
24772        lsp::DiagnosticSeverity::INFORMATION => colors.info,
24773        lsp::DiagnosticSeverity::HINT => colors.info,
24774        _ => colors.ignored,
24775    }
24776}
24777
24778pub fn styled_runs_for_code_label<'a>(
24779    label: &'a CodeLabel,
24780    syntax_theme: &'a theme::SyntaxTheme,
24781) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
24782    let fade_out = HighlightStyle {
24783        fade_out: Some(0.35),
24784        ..Default::default()
24785    };
24786
24787    let mut prev_end = label.filter_range.end;
24788    label
24789        .runs
24790        .iter()
24791        .enumerate()
24792        .flat_map(move |(ix, (range, highlight_id))| {
24793            let style = if let Some(style) = highlight_id.style(syntax_theme) {
24794                style
24795            } else {
24796                return Default::default();
24797            };
24798            let muted_style = style.highlight(fade_out);
24799
24800            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
24801            if range.start >= label.filter_range.end {
24802                if range.start > prev_end {
24803                    runs.push((prev_end..range.start, fade_out));
24804                }
24805                runs.push((range.clone(), muted_style));
24806            } else if range.end <= label.filter_range.end {
24807                runs.push((range.clone(), style));
24808            } else {
24809                runs.push((range.start..label.filter_range.end, style));
24810                runs.push((label.filter_range.end..range.end, muted_style));
24811            }
24812            prev_end = cmp::max(prev_end, range.end);
24813
24814            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
24815                runs.push((prev_end..label.text.len(), fade_out));
24816            }
24817
24818            runs
24819        })
24820}
24821
24822pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
24823    let mut prev_index = 0;
24824    let mut prev_codepoint: Option<char> = None;
24825    text.char_indices()
24826        .chain([(text.len(), '\0')])
24827        .filter_map(move |(index, codepoint)| {
24828            let prev_codepoint = prev_codepoint.replace(codepoint)?;
24829            let is_boundary = index == text.len()
24830                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
24831                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
24832            if is_boundary {
24833                let chunk = &text[prev_index..index];
24834                prev_index = index;
24835                Some(chunk)
24836            } else {
24837                None
24838            }
24839        })
24840}
24841
24842/// Given a string of text immediately before the cursor, iterates over possible
24843/// strings a snippet could match to. More precisely: returns an iterator over
24844/// suffixes of `text` created by splitting at word boundaries (before & after
24845/// every non-word character).
24846///
24847/// Shorter suffixes are returned first.
24848pub(crate) fn snippet_candidate_suffixes(
24849    text: &str,
24850    is_word_char: impl Fn(char) -> bool,
24851) -> impl std::iter::Iterator<Item = &str> {
24852    let mut prev_index = text.len();
24853    let mut prev_codepoint = None;
24854    text.char_indices()
24855        .rev()
24856        .chain([(0, '\0')])
24857        .filter_map(move |(index, codepoint)| {
24858            let prev_index = std::mem::replace(&mut prev_index, index);
24859            let prev_codepoint = prev_codepoint.replace(codepoint)?;
24860            if is_word_char(prev_codepoint) && is_word_char(codepoint) {
24861                None
24862            } else {
24863                let chunk = &text[prev_index..]; // go to end of string
24864                Some(chunk)
24865            }
24866        })
24867}
24868
24869pub trait RangeToAnchorExt: Sized {
24870    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
24871
24872    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
24873        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot());
24874        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
24875    }
24876}
24877
24878impl<T: ToOffset> RangeToAnchorExt for Range<T> {
24879    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
24880        let start_offset = self.start.to_offset(snapshot);
24881        let end_offset = self.end.to_offset(snapshot);
24882        if start_offset == end_offset {
24883            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
24884        } else {
24885            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
24886        }
24887    }
24888}
24889
24890pub trait RowExt {
24891    fn as_f64(&self) -> f64;
24892
24893    fn next_row(&self) -> Self;
24894
24895    fn previous_row(&self) -> Self;
24896
24897    fn minus(&self, other: Self) -> u32;
24898}
24899
24900impl RowExt for DisplayRow {
24901    fn as_f64(&self) -> f64 {
24902        self.0 as _
24903    }
24904
24905    fn next_row(&self) -> Self {
24906        Self(self.0 + 1)
24907    }
24908
24909    fn previous_row(&self) -> Self {
24910        Self(self.0.saturating_sub(1))
24911    }
24912
24913    fn minus(&self, other: Self) -> u32 {
24914        self.0 - other.0
24915    }
24916}
24917
24918impl RowExt for MultiBufferRow {
24919    fn as_f64(&self) -> f64 {
24920        self.0 as _
24921    }
24922
24923    fn next_row(&self) -> Self {
24924        Self(self.0 + 1)
24925    }
24926
24927    fn previous_row(&self) -> Self {
24928        Self(self.0.saturating_sub(1))
24929    }
24930
24931    fn minus(&self, other: Self) -> u32 {
24932        self.0 - other.0
24933    }
24934}
24935
24936trait RowRangeExt {
24937    type Row;
24938
24939    fn len(&self) -> usize;
24940
24941    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
24942}
24943
24944impl RowRangeExt for Range<MultiBufferRow> {
24945    type Row = MultiBufferRow;
24946
24947    fn len(&self) -> usize {
24948        (self.end.0 - self.start.0) as usize
24949    }
24950
24951    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
24952        (self.start.0..self.end.0).map(MultiBufferRow)
24953    }
24954}
24955
24956impl RowRangeExt for Range<DisplayRow> {
24957    type Row = DisplayRow;
24958
24959    fn len(&self) -> usize {
24960        (self.end.0 - self.start.0) as usize
24961    }
24962
24963    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
24964        (self.start.0..self.end.0).map(DisplayRow)
24965    }
24966}
24967
24968/// If select range has more than one line, we
24969/// just point the cursor to range.start.
24970fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
24971    if range.start.row == range.end.row {
24972        range
24973    } else {
24974        range.start..range.start
24975    }
24976}
24977pub struct KillRing(ClipboardItem);
24978impl Global for KillRing {}
24979
24980const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
24981
24982enum BreakpointPromptEditAction {
24983    Log,
24984    Condition,
24985    HitCondition,
24986}
24987
24988struct BreakpointPromptEditor {
24989    pub(crate) prompt: Entity<Editor>,
24990    editor: WeakEntity<Editor>,
24991    breakpoint_anchor: Anchor,
24992    breakpoint: Breakpoint,
24993    edit_action: BreakpointPromptEditAction,
24994    block_ids: HashSet<CustomBlockId>,
24995    editor_margins: Arc<Mutex<EditorMargins>>,
24996    _subscriptions: Vec<Subscription>,
24997}
24998
24999impl BreakpointPromptEditor {
25000    const MAX_LINES: u8 = 4;
25001
25002    fn new(
25003        editor: WeakEntity<Editor>,
25004        breakpoint_anchor: Anchor,
25005        breakpoint: Breakpoint,
25006        edit_action: BreakpointPromptEditAction,
25007        window: &mut Window,
25008        cx: &mut Context<Self>,
25009    ) -> Self {
25010        let base_text = match edit_action {
25011            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
25012            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
25013            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
25014        }
25015        .map(|msg| msg.to_string())
25016        .unwrap_or_default();
25017
25018        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
25019        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
25020
25021        let prompt = cx.new(|cx| {
25022            let mut prompt = Editor::new(
25023                EditorMode::AutoHeight {
25024                    min_lines: 1,
25025                    max_lines: Some(Self::MAX_LINES as usize),
25026                },
25027                buffer,
25028                None,
25029                window,
25030                cx,
25031            );
25032            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
25033            prompt.set_show_cursor_when_unfocused(false, cx);
25034            prompt.set_placeholder_text(
25035                match edit_action {
25036                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
25037                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
25038                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
25039                },
25040                window,
25041                cx,
25042            );
25043
25044            prompt
25045        });
25046
25047        Self {
25048            prompt,
25049            editor,
25050            breakpoint_anchor,
25051            breakpoint,
25052            edit_action,
25053            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
25054            block_ids: Default::default(),
25055            _subscriptions: vec![],
25056        }
25057    }
25058
25059    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
25060        self.block_ids.extend(block_ids)
25061    }
25062
25063    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
25064        if let Some(editor) = self.editor.upgrade() {
25065            let message = self
25066                .prompt
25067                .read(cx)
25068                .buffer
25069                .read(cx)
25070                .as_singleton()
25071                .expect("A multi buffer in breakpoint prompt isn't possible")
25072                .read(cx)
25073                .as_rope()
25074                .to_string();
25075
25076            editor.update(cx, |editor, cx| {
25077                editor.edit_breakpoint_at_anchor(
25078                    self.breakpoint_anchor,
25079                    self.breakpoint.clone(),
25080                    match self.edit_action {
25081                        BreakpointPromptEditAction::Log => {
25082                            BreakpointEditAction::EditLogMessage(message.into())
25083                        }
25084                        BreakpointPromptEditAction::Condition => {
25085                            BreakpointEditAction::EditCondition(message.into())
25086                        }
25087                        BreakpointPromptEditAction::HitCondition => {
25088                            BreakpointEditAction::EditHitCondition(message.into())
25089                        }
25090                    },
25091                    cx,
25092                );
25093
25094                editor.remove_blocks(self.block_ids.clone(), None, cx);
25095                cx.focus_self(window);
25096            });
25097        }
25098    }
25099
25100    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
25101        self.editor
25102            .update(cx, |editor, cx| {
25103                editor.remove_blocks(self.block_ids.clone(), None, cx);
25104                window.focus(&editor.focus_handle);
25105            })
25106            .log_err();
25107    }
25108
25109    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
25110        let settings = ThemeSettings::get_global(cx);
25111        let text_style = TextStyle {
25112            color: if self.prompt.read(cx).read_only(cx) {
25113                cx.theme().colors().text_disabled
25114            } else {
25115                cx.theme().colors().text
25116            },
25117            font_family: settings.buffer_font.family.clone(),
25118            font_fallbacks: settings.buffer_font.fallbacks.clone(),
25119            font_size: settings.buffer_font_size(cx).into(),
25120            font_weight: settings.buffer_font.weight,
25121            line_height: relative(settings.buffer_line_height.value()),
25122            ..Default::default()
25123        };
25124        EditorElement::new(
25125            &self.prompt,
25126            EditorStyle {
25127                background: cx.theme().colors().editor_background,
25128                local_player: cx.theme().players().local(),
25129                text: text_style,
25130                ..Default::default()
25131            },
25132        )
25133    }
25134}
25135
25136impl Render for BreakpointPromptEditor {
25137    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
25138        let editor_margins = *self.editor_margins.lock();
25139        let gutter_dimensions = editor_margins.gutter;
25140        h_flex()
25141            .key_context("Editor")
25142            .bg(cx.theme().colors().editor_background)
25143            .border_y_1()
25144            .border_color(cx.theme().status().info_border)
25145            .size_full()
25146            .py(window.line_height() / 2.5)
25147            .on_action(cx.listener(Self::confirm))
25148            .on_action(cx.listener(Self::cancel))
25149            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
25150            .child(div().flex_1().child(self.render_prompt_editor(cx)))
25151    }
25152}
25153
25154impl Focusable for BreakpointPromptEditor {
25155    fn focus_handle(&self, cx: &App) -> FocusHandle {
25156        self.prompt.focus_handle(cx)
25157    }
25158}
25159
25160fn all_edits_insertions_or_deletions(
25161    edits: &Vec<(Range<Anchor>, Arc<str>)>,
25162    snapshot: &MultiBufferSnapshot,
25163) -> bool {
25164    let mut all_insertions = true;
25165    let mut all_deletions = true;
25166
25167    for (range, new_text) in edits.iter() {
25168        let range_is_empty = range.to_offset(snapshot).is_empty();
25169        let text_is_empty = new_text.is_empty();
25170
25171        if range_is_empty != text_is_empty {
25172            if range_is_empty {
25173                all_deletions = false;
25174            } else {
25175                all_insertions = false;
25176            }
25177        } else {
25178            return false;
25179        }
25180
25181        if !all_insertions && !all_deletions {
25182            return false;
25183        }
25184    }
25185    all_insertions || all_deletions
25186}
25187
25188struct MissingEditPredictionKeybindingTooltip;
25189
25190impl Render for MissingEditPredictionKeybindingTooltip {
25191    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
25192        ui::tooltip_container(cx, |container, cx| {
25193            container
25194                .flex_shrink_0()
25195                .max_w_80()
25196                .min_h(rems_from_px(124.))
25197                .justify_between()
25198                .child(
25199                    v_flex()
25200                        .flex_1()
25201                        .text_ui_sm(cx)
25202                        .child(Label::new("Conflict with Accept Keybinding"))
25203                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
25204                )
25205                .child(
25206                    h_flex()
25207                        .pb_1()
25208                        .gap_1()
25209                        .items_end()
25210                        .w_full()
25211                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
25212                            window.dispatch_action(zed_actions::OpenKeymapFile.boxed_clone(), cx)
25213                        }))
25214                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
25215                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
25216                        })),
25217                )
25218        })
25219    }
25220}
25221
25222#[derive(Debug, Clone, Copy, PartialEq)]
25223pub struct LineHighlight {
25224    pub background: Background,
25225    pub border: Option<gpui::Hsla>,
25226    pub include_gutter: bool,
25227    pub type_id: Option<TypeId>,
25228}
25229
25230struct LineManipulationResult {
25231    pub new_text: String,
25232    pub line_count_before: usize,
25233    pub line_count_after: usize,
25234}
25235
25236fn render_diff_hunk_controls(
25237    row: u32,
25238    status: &DiffHunkStatus,
25239    hunk_range: Range<Anchor>,
25240    is_created_file: bool,
25241    line_height: Pixels,
25242    editor: &Entity<Editor>,
25243    _window: &mut Window,
25244    cx: &mut App,
25245) -> AnyElement {
25246    h_flex()
25247        .h(line_height)
25248        .mr_1()
25249        .gap_1()
25250        .px_0p5()
25251        .pb_1()
25252        .border_x_1()
25253        .border_b_1()
25254        .border_color(cx.theme().colors().border_variant)
25255        .rounded_b_lg()
25256        .bg(cx.theme().colors().editor_background)
25257        .gap_1()
25258        .block_mouse_except_scroll()
25259        .shadow_md()
25260        .child(if status.has_secondary_hunk() {
25261            Button::new(("stage", row as u64), "Stage")
25262                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
25263                .tooltip({
25264                    let focus_handle = editor.focus_handle(cx);
25265                    move |_window, cx| {
25266                        Tooltip::for_action_in(
25267                            "Stage Hunk",
25268                            &::git::ToggleStaged,
25269                            &focus_handle,
25270                            cx,
25271                        )
25272                    }
25273                })
25274                .on_click({
25275                    let editor = editor.clone();
25276                    move |_event, _window, cx| {
25277                        editor.update(cx, |editor, cx| {
25278                            editor.stage_or_unstage_diff_hunks(
25279                                true,
25280                                vec![hunk_range.start..hunk_range.start],
25281                                cx,
25282                            );
25283                        });
25284                    }
25285                })
25286        } else {
25287            Button::new(("unstage", row as u64), "Unstage")
25288                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
25289                .tooltip({
25290                    let focus_handle = editor.focus_handle(cx);
25291                    move |_window, cx| {
25292                        Tooltip::for_action_in(
25293                            "Unstage Hunk",
25294                            &::git::ToggleStaged,
25295                            &focus_handle,
25296                            cx,
25297                        )
25298                    }
25299                })
25300                .on_click({
25301                    let editor = editor.clone();
25302                    move |_event, _window, cx| {
25303                        editor.update(cx, |editor, cx| {
25304                            editor.stage_or_unstage_diff_hunks(
25305                                false,
25306                                vec![hunk_range.start..hunk_range.start],
25307                                cx,
25308                            );
25309                        });
25310                    }
25311                })
25312        })
25313        .child(
25314            Button::new(("restore", row as u64), "Restore")
25315                .tooltip({
25316                    let focus_handle = editor.focus_handle(cx);
25317                    move |_window, cx| {
25318                        Tooltip::for_action_in("Restore Hunk", &::git::Restore, &focus_handle, cx)
25319                    }
25320                })
25321                .on_click({
25322                    let editor = editor.clone();
25323                    move |_event, window, cx| {
25324                        editor.update(cx, |editor, cx| {
25325                            let snapshot = editor.snapshot(window, cx);
25326                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot());
25327                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
25328                        });
25329                    }
25330                })
25331                .disabled(is_created_file),
25332        )
25333        .when(
25334            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
25335            |el| {
25336                el.child(
25337                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
25338                        .shape(IconButtonShape::Square)
25339                        .icon_size(IconSize::Small)
25340                        // .disabled(!has_multiple_hunks)
25341                        .tooltip({
25342                            let focus_handle = editor.focus_handle(cx);
25343                            move |_window, cx| {
25344                                Tooltip::for_action_in("Next Hunk", &GoToHunk, &focus_handle, cx)
25345                            }
25346                        })
25347                        .on_click({
25348                            let editor = editor.clone();
25349                            move |_event, window, cx| {
25350                                editor.update(cx, |editor, cx| {
25351                                    let snapshot = editor.snapshot(window, cx);
25352                                    let position =
25353                                        hunk_range.end.to_point(&snapshot.buffer_snapshot());
25354                                    editor.go_to_hunk_before_or_after_position(
25355                                        &snapshot,
25356                                        position,
25357                                        Direction::Next,
25358                                        window,
25359                                        cx,
25360                                    );
25361                                    editor.expand_selected_diff_hunks(cx);
25362                                });
25363                            }
25364                        }),
25365                )
25366                .child(
25367                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
25368                        .shape(IconButtonShape::Square)
25369                        .icon_size(IconSize::Small)
25370                        // .disabled(!has_multiple_hunks)
25371                        .tooltip({
25372                            let focus_handle = editor.focus_handle(cx);
25373                            move |_window, cx| {
25374                                Tooltip::for_action_in(
25375                                    "Previous Hunk",
25376                                    &GoToPreviousHunk,
25377                                    &focus_handle,
25378                                    cx,
25379                                )
25380                            }
25381                        })
25382                        .on_click({
25383                            let editor = editor.clone();
25384                            move |_event, window, cx| {
25385                                editor.update(cx, |editor, cx| {
25386                                    let snapshot = editor.snapshot(window, cx);
25387                                    let point =
25388                                        hunk_range.start.to_point(&snapshot.buffer_snapshot());
25389                                    editor.go_to_hunk_before_or_after_position(
25390                                        &snapshot,
25391                                        point,
25392                                        Direction::Prev,
25393                                        window,
25394                                        cx,
25395                                    );
25396                                    editor.expand_selected_diff_hunks(cx);
25397                                });
25398                            }
25399                        }),
25400                )
25401            },
25402        )
25403        .into_any_element()
25404}
25405
25406pub fn multibuffer_context_lines(cx: &App) -> u32 {
25407    EditorSettings::try_get(cx)
25408        .map(|settings| settings.excerpt_context_lines)
25409        .unwrap_or(2)
25410        .min(32)
25411}