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 bracket_colorization;
   17mod clangd_ext;
   18pub mod code_context_menus;
   19pub mod display_map;
   20mod editor_settings;
   21mod element;
   22mod git;
   23mod highlight_matching_bracket;
   24mod hover_links;
   25pub mod hover_popover;
   26mod indent_guides;
   27mod inlays;
   28pub mod items;
   29mod jsx_tag_auto_close;
   30mod linked_editing_ranges;
   31mod lsp_colors;
   32mod lsp_ext;
   33mod mouse_context_menu;
   34pub mod movement;
   35mod persistence;
   36mod rust_analyzer_ext;
   37pub mod scroll;
   38mod selections_collection;
   39pub mod tasks;
   40
   41#[cfg(test)]
   42mod code_completion_tests;
   43#[cfg(test)]
   44mod edit_prediction_tests;
   45#[cfg(test)]
   46mod editor_tests;
   47mod signature_help;
   48#[cfg(any(test, feature = "test-support"))]
   49pub mod test;
   50
   51pub(crate) use actions::*;
   52pub use display_map::{ChunkRenderer, ChunkRendererContext, DisplayPoint, FoldPlaceholder};
   53pub use edit_prediction::Direction;
   54pub use editor_settings::{
   55    CurrentLineHighlight, DocumentColorsRenderMode, EditorSettings, HideMouseMode,
   56    ScrollBeyondLastLine, ScrollbarAxes, SearchSettings, ShowMinimap,
   57};
   58pub use element::{
   59    CursorLayout, EditorElement, HighlightedRange, HighlightedRangeLine, PointForPosition,
   60};
   61pub use git::blame::BlameRenderer;
   62pub use hover_popover::hover_markdown_style;
   63pub use inlays::Inlay;
   64pub use items::MAX_TAB_TITLE_LEN;
   65pub use lsp::CompletionContext;
   66pub use lsp_ext::lsp_tasks;
   67pub use multi_buffer::{
   68    Anchor, AnchorRangeExt, ExcerptId, ExcerptRange, MultiBuffer, MultiBufferSnapshot, PathKey,
   69    RowInfo, ToOffset, ToPoint,
   70};
   71pub use text::Bias;
   72
   73use ::git::{
   74    Restore,
   75    blame::{BlameEntry, ParsedCommitMessage},
   76    status::FileStatus,
   77};
   78use aho_corasick::AhoCorasick;
   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, LanguageName, OffsetRangeExt, Point, Runnable, RunnableRange, Selection,
  122    SelectionGoal, TextObject, TransactionId, TreeSitterOptions, WordsQuery,
  123    language_settings::{
  124        self, LanguageSettings, LspInsertMode, RewrapBehavior, WordsCompletionMode,
  125        all_language_settings, 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    collections::hash_map,
  179    iter::{self, Peekable},
  180    mem,
  181    num::NonZeroU32,
  182    ops::{Deref, DerefMut, Not, Range, RangeInclusive},
  183    path::{Path, PathBuf},
  184    rc::Rc,
  185    sync::Arc,
  186    time::{Duration, Instant},
  187};
  188use task::{ResolvedTask, RunnableTag, TaskTemplate, TaskVariables};
  189use text::{BufferId, FromAnchor, OffsetUtf16, Rope, ToOffset as _};
  190use theme::{
  191    ActiveTheme, PlayerColor, StatusColors, SyntaxTheme, Theme, ThemeSettings,
  192    observe_buffer_font_size_adjustment,
  193};
  194use ui::{
  195    ButtonSize, ButtonStyle, ContextMenu, Disclosure, IconButton, IconButtonShape, IconName,
  196    IconSize, Indicator, Key, Tooltip, h_flex, prelude::*, scrollbars::ScrollbarAutoHide,
  197};
  198use util::{RangeExt, ResultExt, TryFutureExt, maybe, post_inc};
  199use workspace::{
  200    CollaboratorId, Item as WorkspaceItem, ItemId, ItemNavHistory, OpenInTerminal, OpenTerminal,
  201    RestoreOnStartupBehavior, SERIALIZATION_THROTTLE_TIME, SplitDirection, TabBarSettings, Toast,
  202    ViewId, Workspace, WorkspaceId, WorkspaceSettings,
  203    item::{ItemBufferKind, ItemHandle, PreviewTabsSettings, SaveOptions},
  204    notifications::{DetachAndPromptErr, NotificationId, NotifyTaskExt},
  205    searchable::SearchEvent,
  206};
  207
  208use crate::{
  209    code_context_menus::CompletionsMenuSource,
  210    editor_settings::MultiCursorModifier,
  211    hover_links::{find_url, find_url_from_range},
  212    inlays::{
  213        InlineValueCache,
  214        inlay_hints::{LspInlayHintData, inlay_hint_settings},
  215    },
  216    scroll::{ScrollOffset, ScrollPixelOffset},
  217    selections_collection::resolve_selections_wrapping_blocks,
  218    signature_help::{SignatureHelpHiddenBy, SignatureHelpState},
  219};
  220
  221pub const FILE_HEADER_HEIGHT: u32 = 2;
  222pub const MULTI_BUFFER_EXCERPT_HEADER_HEIGHT: u32 = 1;
  223const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500);
  224const MAX_LINE_LEN: usize = 1024;
  225const MIN_NAVIGATION_HISTORY_ROW_DELTA: i64 = 10;
  226const MAX_SELECTION_HISTORY_LEN: usize = 1024;
  227pub(crate) const CURSORS_VISIBLE_FOR: Duration = Duration::from_millis(2000);
  228#[doc(hidden)]
  229pub const CODE_ACTIONS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(250);
  230pub const SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(100);
  231
  232pub(crate) const CODE_ACTION_TIMEOUT: Duration = Duration::from_secs(5);
  233pub(crate) const FORMAT_TIMEOUT: Duration = Duration::from_secs(5);
  234pub(crate) const SCROLL_CENTER_TOP_BOTTOM_DEBOUNCE_TIMEOUT: Duration = Duration::from_secs(1);
  235pub const FETCH_COLORS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(150);
  236
  237pub(crate) const EDIT_PREDICTION_KEY_CONTEXT: &str = "edit_prediction";
  238pub(crate) const EDIT_PREDICTION_CONFLICT_KEY_CONTEXT: &str = "edit_prediction_conflict";
  239pub(crate) const MINIMAP_FONT_SIZE: AbsoluteLength = AbsoluteLength::Pixels(px(2.));
  240
  241pub type RenderDiffHunkControlsFn = Arc<
  242    dyn Fn(
  243        u32,
  244        &DiffHunkStatus,
  245        Range<Anchor>,
  246        bool,
  247        Pixels,
  248        &Entity<Editor>,
  249        &mut Window,
  250        &mut App,
  251    ) -> AnyElement,
  252>;
  253
  254enum ReportEditorEvent {
  255    Saved { auto_saved: bool },
  256    EditorOpened,
  257    Closed,
  258}
  259
  260impl ReportEditorEvent {
  261    pub fn event_type(&self) -> &'static str {
  262        match self {
  263            Self::Saved { .. } => "Editor Saved",
  264            Self::EditorOpened => "Editor Opened",
  265            Self::Closed => "Editor Closed",
  266        }
  267    }
  268}
  269
  270pub enum ActiveDebugLine {}
  271pub enum DebugStackFrameLine {}
  272enum DocumentHighlightRead {}
  273enum DocumentHighlightWrite {}
  274enum InputComposition {}
  275pub enum PendingInput {}
  276enum SelectedTextHighlight {}
  277
  278pub enum ConflictsOuter {}
  279pub enum ConflictsOurs {}
  280pub enum ConflictsTheirs {}
  281pub enum ConflictsOursMarker {}
  282pub enum ConflictsTheirsMarker {}
  283
  284#[derive(Debug, Copy, Clone, PartialEq, Eq)]
  285pub enum Navigated {
  286    Yes,
  287    No,
  288}
  289
  290impl Navigated {
  291    pub fn from_bool(yes: bool) -> Navigated {
  292        if yes { Navigated::Yes } else { Navigated::No }
  293    }
  294}
  295
  296#[derive(Debug, Clone, PartialEq, Eq)]
  297enum DisplayDiffHunk {
  298    Folded {
  299        display_row: DisplayRow,
  300    },
  301    Unfolded {
  302        is_created_file: bool,
  303        diff_base_byte_range: Range<usize>,
  304        display_row_range: Range<DisplayRow>,
  305        multi_buffer_range: Range<Anchor>,
  306        status: DiffHunkStatus,
  307    },
  308}
  309
  310pub enum HideMouseCursorOrigin {
  311    TypingAction,
  312    MovementAction,
  313}
  314
  315pub fn init(cx: &mut App) {
  316    cx.set_global(GlobalBlameRenderer(Arc::new(())));
  317
  318    workspace::register_project_item::<Editor>(cx);
  319    workspace::FollowableViewRegistry::register::<Editor>(cx);
  320    workspace::register_serializable_item::<Editor>(cx);
  321
  322    cx.observe_new(
  323        |workspace: &mut Workspace, _: Option<&mut Window>, _cx: &mut Context<Workspace>| {
  324            workspace.register_action(Editor::new_file);
  325            workspace.register_action(Editor::new_file_split);
  326            workspace.register_action(Editor::new_file_vertical);
  327            workspace.register_action(Editor::new_file_horizontal);
  328            workspace.register_action(Editor::cancel_language_server_work);
  329            workspace.register_action(Editor::toggle_focus);
  330        },
  331    )
  332    .detach();
  333
  334    cx.on_action(move |_: &workspace::NewFile, cx| {
  335        let app_state = workspace::AppState::global(cx);
  336        if let Some(app_state) = app_state.upgrade() {
  337            workspace::open_new(
  338                Default::default(),
  339                app_state,
  340                cx,
  341                |workspace, window, cx| {
  342                    Editor::new_file(workspace, &Default::default(), window, cx)
  343                },
  344            )
  345            .detach();
  346        }
  347    });
  348    cx.on_action(move |_: &workspace::NewWindow, cx| {
  349        let app_state = workspace::AppState::global(cx);
  350        if let Some(app_state) = app_state.upgrade() {
  351            workspace::open_new(
  352                Default::default(),
  353                app_state,
  354                cx,
  355                |workspace, window, cx| {
  356                    cx.activate(true);
  357                    Editor::new_file(workspace, &Default::default(), window, cx)
  358                },
  359            )
  360            .detach();
  361        }
  362    });
  363}
  364
  365pub fn set_blame_renderer(renderer: impl BlameRenderer + 'static, cx: &mut App) {
  366    cx.set_global(GlobalBlameRenderer(Arc::new(renderer)));
  367}
  368
  369pub trait DiagnosticRenderer {
  370    fn render_group(
  371        &self,
  372        diagnostic_group: Vec<DiagnosticEntryRef<'_, Point>>,
  373        buffer_id: BufferId,
  374        snapshot: EditorSnapshot,
  375        editor: WeakEntity<Editor>,
  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        cx: &mut App,
  385    ) -> Option<Entity<markdown::Markdown>>;
  386
  387    fn open_link(
  388        &self,
  389        editor: &mut Editor,
  390        link: SharedString,
  391        window: &mut Window,
  392        cx: &mut Context<Editor>,
  393    );
  394}
  395
  396pub(crate) struct GlobalDiagnosticRenderer(pub Arc<dyn DiagnosticRenderer>);
  397
  398impl GlobalDiagnosticRenderer {
  399    fn global(cx: &App) -> Option<Arc<dyn DiagnosticRenderer>> {
  400        cx.try_global::<Self>().map(|g| g.0.clone())
  401    }
  402}
  403
  404impl gpui::Global for GlobalDiagnosticRenderer {}
  405pub fn set_diagnostic_renderer(renderer: impl DiagnosticRenderer + 'static, cx: &mut App) {
  406    cx.set_global(GlobalDiagnosticRenderer(Arc::new(renderer)));
  407}
  408
  409pub struct SearchWithinRange;
  410
  411trait InvalidationRegion {
  412    fn ranges(&self) -> &[Range<Anchor>];
  413}
  414
  415#[derive(Clone, Debug, PartialEq)]
  416pub enum SelectPhase {
  417    Begin {
  418        position: DisplayPoint,
  419        add: bool,
  420        click_count: usize,
  421    },
  422    BeginColumnar {
  423        position: DisplayPoint,
  424        reset: bool,
  425        mode: ColumnarMode,
  426        goal_column: u32,
  427    },
  428    Extend {
  429        position: DisplayPoint,
  430        click_count: usize,
  431    },
  432    Update {
  433        position: DisplayPoint,
  434        goal_column: u32,
  435        scroll_delta: gpui::Point<f32>,
  436    },
  437    End,
  438}
  439
  440#[derive(Clone, Debug, PartialEq)]
  441pub enum ColumnarMode {
  442    FromMouse,
  443    FromSelection,
  444}
  445
  446#[derive(Clone, Debug)]
  447pub enum SelectMode {
  448    Character,
  449    Word(Range<Anchor>),
  450    Line(Range<Anchor>),
  451    All,
  452}
  453
  454#[derive(Copy, Clone, Default, PartialEq, Eq, Debug)]
  455pub enum SizingBehavior {
  456    /// The editor will layout itself using `size_full` and will include the vertical
  457    /// scroll margin as requested by user settings.
  458    #[default]
  459    Default,
  460    /// The editor will layout itself using `size_full`, but will not have any
  461    /// vertical overscroll.
  462    ExcludeOverscrollMargin,
  463    /// The editor will request a vertical size according to its content and will be
  464    /// layouted without a vertical scroll margin.
  465    SizeByContent,
  466}
  467
  468#[derive(Clone, PartialEq, Eq, Debug)]
  469pub enum EditorMode {
  470    SingleLine,
  471    AutoHeight {
  472        min_lines: usize,
  473        max_lines: Option<usize>,
  474    },
  475    Full {
  476        /// When set to `true`, the editor will scale its UI elements with the buffer font size.
  477        scale_ui_elements_with_buffer_font_size: bool,
  478        /// When set to `true`, the editor will render a background for the active line.
  479        show_active_line_background: bool,
  480        /// Determines the sizing behavior for this editor
  481        sizing_behavior: SizingBehavior,
  482    },
  483    Minimap {
  484        parent: WeakEntity<Editor>,
  485    },
  486}
  487
  488impl EditorMode {
  489    pub fn full() -> Self {
  490        Self::Full {
  491            scale_ui_elements_with_buffer_font_size: true,
  492            show_active_line_background: true,
  493            sizing_behavior: SizingBehavior::Default,
  494        }
  495    }
  496
  497    #[inline]
  498    pub fn is_full(&self) -> bool {
  499        matches!(self, Self::Full { .. })
  500    }
  501
  502    #[inline]
  503    pub fn is_single_line(&self) -> bool {
  504        matches!(self, Self::SingleLine { .. })
  505    }
  506
  507    #[inline]
  508    fn is_minimap(&self) -> bool {
  509        matches!(self, Self::Minimap { .. })
  510    }
  511}
  512
  513#[derive(Copy, Clone, Debug)]
  514pub enum SoftWrap {
  515    /// Prefer not to wrap at all.
  516    ///
  517    /// Note: this is currently internal, as actually limited by [`crate::MAX_LINE_LEN`] until it wraps.
  518    /// The mode is used inside git diff hunks, where it's seems currently more useful to not wrap as much as possible.
  519    GitDiff,
  520    /// Prefer a single line generally, unless an overly long line is encountered.
  521    None,
  522    /// Soft wrap lines that exceed the editor width.
  523    EditorWidth,
  524    /// Soft wrap lines at the preferred line length.
  525    Column(u32),
  526    /// Soft wrap line at the preferred line length or the editor width (whichever is smaller).
  527    Bounded(u32),
  528}
  529
  530#[derive(Clone)]
  531pub struct EditorStyle {
  532    pub background: Hsla,
  533    pub border: Hsla,
  534    pub local_player: PlayerColor,
  535    pub text: TextStyle,
  536    pub scrollbar_width: Pixels,
  537    pub syntax: Arc<SyntaxTheme>,
  538    pub status: StatusColors,
  539    pub inlay_hints_style: HighlightStyle,
  540    pub edit_prediction_styles: EditPredictionStyles,
  541    pub unnecessary_code_fade: f32,
  542    pub show_underlines: bool,
  543}
  544
  545impl Default for EditorStyle {
  546    fn default() -> Self {
  547        Self {
  548            background: Hsla::default(),
  549            border: Hsla::default(),
  550            local_player: PlayerColor::default(),
  551            text: TextStyle::default(),
  552            scrollbar_width: Pixels::default(),
  553            syntax: Default::default(),
  554            // HACK: Status colors don't have a real default.
  555            // We should look into removing the status colors from the editor
  556            // style and retrieve them directly from the theme.
  557            status: StatusColors::dark(),
  558            inlay_hints_style: HighlightStyle::default(),
  559            edit_prediction_styles: EditPredictionStyles {
  560                insertion: HighlightStyle::default(),
  561                whitespace: HighlightStyle::default(),
  562            },
  563            unnecessary_code_fade: Default::default(),
  564            show_underlines: true,
  565        }
  566    }
  567}
  568
  569pub fn make_inlay_hints_style(cx: &mut App) -> HighlightStyle {
  570    let show_background = language_settings::language_settings(None, None, cx)
  571        .inlay_hints
  572        .show_background;
  573
  574    let mut style = cx.theme().syntax().get("hint");
  575
  576    if style.color.is_none() {
  577        style.color = Some(cx.theme().status().hint);
  578    }
  579
  580    if !show_background {
  581        style.background_color = None;
  582        return style;
  583    }
  584
  585    if style.background_color.is_none() {
  586        style.background_color = Some(cx.theme().status().hint_background);
  587    }
  588
  589    style
  590}
  591
  592pub fn make_suggestion_styles(cx: &mut App) -> EditPredictionStyles {
  593    EditPredictionStyles {
  594        insertion: HighlightStyle {
  595            color: Some(cx.theme().status().predictive),
  596            ..HighlightStyle::default()
  597        },
  598        whitespace: HighlightStyle {
  599            background_color: Some(cx.theme().status().created_background),
  600            ..HighlightStyle::default()
  601        },
  602    }
  603}
  604
  605type CompletionId = usize;
  606
  607pub(crate) enum EditDisplayMode {
  608    TabAccept,
  609    DiffPopover,
  610    Inline,
  611}
  612
  613enum EditPrediction {
  614    Edit {
  615        edits: Vec<(Range<Anchor>, Arc<str>)>,
  616        edit_preview: Option<EditPreview>,
  617        display_mode: EditDisplayMode,
  618        snapshot: BufferSnapshot,
  619    },
  620    /// Move to a specific location in the active editor
  621    MoveWithin {
  622        target: Anchor,
  623        snapshot: BufferSnapshot,
  624    },
  625    /// Move to a specific location in a different editor (not the active one)
  626    MoveOutside {
  627        target: language::Anchor,
  628        snapshot: BufferSnapshot,
  629    },
  630}
  631
  632struct EditPredictionState {
  633    inlay_ids: Vec<InlayId>,
  634    completion: EditPrediction,
  635    completion_id: Option<SharedString>,
  636    invalidation_range: Option<Range<Anchor>>,
  637}
  638
  639enum EditPredictionSettings {
  640    Disabled,
  641    Enabled {
  642        show_in_menu: bool,
  643        preview_requires_modifier: bool,
  644    },
  645}
  646
  647enum EditPredictionHighlight {}
  648
  649#[derive(Debug, Clone)]
  650struct InlineDiagnostic {
  651    message: SharedString,
  652    group_id: usize,
  653    is_primary: bool,
  654    start: Point,
  655    severity: lsp::DiagnosticSeverity,
  656}
  657
  658pub enum MenuEditPredictionsPolicy {
  659    Never,
  660    ByProvider,
  661}
  662
  663pub enum EditPredictionPreview {
  664    /// Modifier is not pressed
  665    Inactive { released_too_fast: bool },
  666    /// Modifier pressed
  667    Active {
  668        since: Instant,
  669        previous_scroll_position: Option<ScrollAnchor>,
  670    },
  671}
  672
  673impl EditPredictionPreview {
  674    pub fn released_too_fast(&self) -> bool {
  675        match self {
  676            EditPredictionPreview::Inactive { released_too_fast } => *released_too_fast,
  677            EditPredictionPreview::Active { .. } => false,
  678        }
  679    }
  680
  681    pub fn set_previous_scroll_position(&mut self, scroll_position: Option<ScrollAnchor>) {
  682        if let EditPredictionPreview::Active {
  683            previous_scroll_position,
  684            ..
  685        } = self
  686        {
  687            *previous_scroll_position = scroll_position;
  688        }
  689    }
  690}
  691
  692pub struct ContextMenuOptions {
  693    pub min_entries_visible: usize,
  694    pub max_entries_visible: usize,
  695    pub placement: Option<ContextMenuPlacement>,
  696}
  697
  698#[derive(Debug, Clone, PartialEq, Eq)]
  699pub enum ContextMenuPlacement {
  700    Above,
  701    Below,
  702}
  703
  704#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug, Default)]
  705struct EditorActionId(usize);
  706
  707impl EditorActionId {
  708    pub fn post_inc(&mut self) -> Self {
  709        let answer = self.0;
  710
  711        *self = Self(answer + 1);
  712
  713        Self(answer)
  714    }
  715}
  716
  717// type GetFieldEditorTheme = dyn Fn(&theme::Theme) -> theme::FieldEditor;
  718// type OverrideTextStyle = dyn Fn(&EditorStyle) -> Option<HighlightStyle>;
  719
  720type BackgroundHighlight = (fn(&Theme) -> Hsla, Arc<[Range<Anchor>]>);
  721type GutterHighlight = (fn(&App) -> Hsla, Vec<Range<Anchor>>);
  722
  723#[derive(Default)]
  724struct ScrollbarMarkerState {
  725    scrollbar_size: Size<Pixels>,
  726    dirty: bool,
  727    markers: Arc<[PaintQuad]>,
  728    pending_refresh: Option<Task<Result<()>>>,
  729}
  730
  731impl ScrollbarMarkerState {
  732    fn should_refresh(&self, scrollbar_size: Size<Pixels>) -> bool {
  733        self.pending_refresh.is_none() && (self.scrollbar_size != scrollbar_size || self.dirty)
  734    }
  735}
  736
  737#[derive(Clone, Copy, PartialEq, Eq)]
  738pub enum MinimapVisibility {
  739    Disabled,
  740    Enabled {
  741        /// The configuration currently present in the users settings.
  742        setting_configuration: bool,
  743        /// Whether to override the currently set visibility from the users setting.
  744        toggle_override: bool,
  745    },
  746}
  747
  748impl MinimapVisibility {
  749    fn for_mode(mode: &EditorMode, cx: &App) -> Self {
  750        if mode.is_full() {
  751            Self::Enabled {
  752                setting_configuration: EditorSettings::get_global(cx).minimap.minimap_enabled(),
  753                toggle_override: false,
  754            }
  755        } else {
  756            Self::Disabled
  757        }
  758    }
  759
  760    fn hidden(&self) -> Self {
  761        match *self {
  762            Self::Enabled {
  763                setting_configuration,
  764                ..
  765            } => Self::Enabled {
  766                setting_configuration,
  767                toggle_override: setting_configuration,
  768            },
  769            Self::Disabled => Self::Disabled,
  770        }
  771    }
  772
  773    fn disabled(&self) -> bool {
  774        matches!(*self, Self::Disabled)
  775    }
  776
  777    fn settings_visibility(&self) -> bool {
  778        match *self {
  779            Self::Enabled {
  780                setting_configuration,
  781                ..
  782            } => setting_configuration,
  783            _ => false,
  784        }
  785    }
  786
  787    fn visible(&self) -> bool {
  788        match *self {
  789            Self::Enabled {
  790                setting_configuration,
  791                toggle_override,
  792            } => setting_configuration ^ toggle_override,
  793            _ => false,
  794        }
  795    }
  796
  797    fn toggle_visibility(&self) -> Self {
  798        match *self {
  799            Self::Enabled {
  800                toggle_override,
  801                setting_configuration,
  802            } => Self::Enabled {
  803                setting_configuration,
  804                toggle_override: !toggle_override,
  805            },
  806            Self::Disabled => Self::Disabled,
  807        }
  808    }
  809}
  810
  811#[derive(Debug, Clone, Copy, PartialEq, Eq)]
  812pub enum BufferSerialization {
  813    All,
  814    NonDirtyBuffers,
  815}
  816
  817impl BufferSerialization {
  818    fn new(restore_unsaved_buffers: bool) -> Self {
  819        if restore_unsaved_buffers {
  820            Self::All
  821        } else {
  822            Self::NonDirtyBuffers
  823        }
  824    }
  825}
  826
  827#[derive(Clone, Debug)]
  828struct RunnableTasks {
  829    templates: Vec<(TaskSourceKind, TaskTemplate)>,
  830    offset: multi_buffer::Anchor,
  831    // We need the column at which the task context evaluation should take place (when we're spawning it via gutter).
  832    column: u32,
  833    // Values of all named captures, including those starting with '_'
  834    extra_variables: HashMap<String, String>,
  835    // Full range of the tagged region. We use it to determine which `extra_variables` to grab for context resolution in e.g. a modal.
  836    context_range: Range<BufferOffset>,
  837}
  838
  839impl RunnableTasks {
  840    fn resolve<'a>(
  841        &'a self,
  842        cx: &'a task::TaskContext,
  843    ) -> impl Iterator<Item = (TaskSourceKind, ResolvedTask)> + 'a {
  844        self.templates.iter().filter_map(|(kind, template)| {
  845            template
  846                .resolve_task(&kind.to_id_base(), cx)
  847                .map(|task| (kind.clone(), task))
  848        })
  849    }
  850}
  851
  852#[derive(Clone)]
  853pub struct ResolvedTasks {
  854    templates: SmallVec<[(TaskSourceKind, ResolvedTask); 1]>,
  855    position: Anchor,
  856}
  857
  858#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
  859struct BufferOffset(usize);
  860
  861/// Addons allow storing per-editor state in other crates (e.g. Vim)
  862pub trait Addon: 'static {
  863    fn extend_key_context(&self, _: &mut KeyContext, _: &App) {}
  864
  865    fn render_buffer_header_controls(
  866        &self,
  867        _: &ExcerptInfo,
  868        _: &Window,
  869        _: &App,
  870    ) -> Option<AnyElement> {
  871        None
  872    }
  873
  874    fn override_status_for_buffer_id(&self, _: BufferId, _: &App) -> Option<FileStatus> {
  875        None
  876    }
  877
  878    fn to_any(&self) -> &dyn std::any::Any;
  879
  880    fn to_any_mut(&mut self) -> Option<&mut dyn std::any::Any> {
  881        None
  882    }
  883}
  884
  885struct ChangeLocation {
  886    current: Option<Vec<Anchor>>,
  887    original: Vec<Anchor>,
  888}
  889impl ChangeLocation {
  890    fn locations(&self) -> &[Anchor] {
  891        self.current.as_ref().unwrap_or(&self.original)
  892    }
  893}
  894
  895/// A set of caret positions, registered when the editor was edited.
  896pub struct ChangeList {
  897    changes: Vec<ChangeLocation>,
  898    /// Currently "selected" change.
  899    position: Option<usize>,
  900}
  901
  902impl ChangeList {
  903    pub fn new() -> Self {
  904        Self {
  905            changes: Vec::new(),
  906            position: None,
  907        }
  908    }
  909
  910    /// Moves to the next change in the list (based on the direction given) and returns the caret positions for the next change.
  911    /// If reaches the end of the list in the direction, returns the corresponding change until called for a different direction.
  912    pub fn next_change(&mut self, count: usize, direction: Direction) -> Option<&[Anchor]> {
  913        if self.changes.is_empty() {
  914            return None;
  915        }
  916
  917        let prev = self.position.unwrap_or(self.changes.len());
  918        let next = if direction == Direction::Prev {
  919            prev.saturating_sub(count)
  920        } else {
  921            (prev + count).min(self.changes.len() - 1)
  922        };
  923        self.position = Some(next);
  924        self.changes.get(next).map(|change| change.locations())
  925    }
  926
  927    /// Adds a new change to the list, resetting the change list position.
  928    pub fn push_to_change_list(&mut self, group: bool, new_positions: Vec<Anchor>) {
  929        self.position.take();
  930        if let Some(last) = self.changes.last_mut()
  931            && group
  932        {
  933            last.current = Some(new_positions)
  934        } else {
  935            self.changes.push(ChangeLocation {
  936                original: new_positions,
  937                current: None,
  938            });
  939        }
  940    }
  941
  942    pub fn last(&self) -> Option<&[Anchor]> {
  943        self.changes.last().map(|change| change.locations())
  944    }
  945
  946    pub fn last_before_grouping(&self) -> Option<&[Anchor]> {
  947        self.changes.last().map(|change| change.original.as_slice())
  948    }
  949
  950    pub fn invert_last_group(&mut self) {
  951        if let Some(last) = self.changes.last_mut()
  952            && let Some(current) = last.current.as_mut()
  953        {
  954            mem::swap(&mut last.original, current);
  955        }
  956    }
  957}
  958
  959#[derive(Clone)]
  960struct InlineBlamePopoverState {
  961    scroll_handle: ScrollHandle,
  962    commit_message: Option<ParsedCommitMessage>,
  963    markdown: Entity<Markdown>,
  964}
  965
  966struct InlineBlamePopover {
  967    position: gpui::Point<Pixels>,
  968    hide_task: Option<Task<()>>,
  969    popover_bounds: Option<Bounds<Pixels>>,
  970    popover_state: InlineBlamePopoverState,
  971    keyboard_grace: bool,
  972}
  973
  974enum SelectionDragState {
  975    /// State when no drag related activity is detected.
  976    None,
  977    /// State when the mouse is down on a selection that is about to be dragged.
  978    ReadyToDrag {
  979        selection: Selection<Anchor>,
  980        click_position: gpui::Point<Pixels>,
  981        mouse_down_time: Instant,
  982    },
  983    /// State when the mouse is dragging the selection in the editor.
  984    Dragging {
  985        selection: Selection<Anchor>,
  986        drop_cursor: Selection<Anchor>,
  987        hide_drop_cursor: bool,
  988    },
  989}
  990
  991enum ColumnarSelectionState {
  992    FromMouse {
  993        selection_tail: Anchor,
  994        display_point: Option<DisplayPoint>,
  995    },
  996    FromSelection {
  997        selection_tail: Anchor,
  998    },
  999}
 1000
 1001/// Represents a breakpoint indicator that shows up when hovering over lines in the gutter that don't have
 1002/// a breakpoint on them.
 1003#[derive(Clone, Copy, Debug, PartialEq, Eq)]
 1004struct PhantomBreakpointIndicator {
 1005    display_row: DisplayRow,
 1006    /// There's a small debounce between hovering over the line and showing the indicator.
 1007    /// We don't want to show the indicator when moving the mouse from editor to e.g. project panel.
 1008    is_active: bool,
 1009    collides_with_existing_breakpoint: bool,
 1010}
 1011
 1012/// Zed's primary implementation of text input, allowing users to edit a [`MultiBuffer`].
 1013///
 1014/// See the [module level documentation](self) for more information.
 1015pub struct Editor {
 1016    focus_handle: FocusHandle,
 1017    last_focused_descendant: Option<WeakFocusHandle>,
 1018    /// The text buffer being edited
 1019    buffer: Entity<MultiBuffer>,
 1020    /// Map of how text in the buffer should be displayed.
 1021    /// Handles soft wraps, folds, fake inlay text insertions, etc.
 1022    pub display_map: Entity<DisplayMap>,
 1023    placeholder_display_map: Option<Entity<DisplayMap>>,
 1024    pub selections: SelectionsCollection,
 1025    pub scroll_manager: ScrollManager,
 1026    /// When inline assist editors are linked, they all render cursors because
 1027    /// typing enters text into each of them, even the ones that aren't focused.
 1028    pub(crate) show_cursor_when_unfocused: bool,
 1029    columnar_selection_state: Option<ColumnarSelectionState>,
 1030    add_selections_state: Option<AddSelectionsState>,
 1031    select_next_state: Option<SelectNextState>,
 1032    select_prev_state: Option<SelectNextState>,
 1033    selection_history: SelectionHistory,
 1034    defer_selection_effects: bool,
 1035    deferred_selection_effects_state: Option<DeferredSelectionEffectsState>,
 1036    autoclose_regions: Vec<AutocloseRegion>,
 1037    snippet_stack: InvalidationStack<SnippetState>,
 1038    select_syntax_node_history: SelectSyntaxNodeHistory,
 1039    ime_transaction: Option<TransactionId>,
 1040    pub diagnostics_max_severity: DiagnosticSeverity,
 1041    active_diagnostics: ActiveDiagnostic,
 1042    show_inline_diagnostics: bool,
 1043    inline_diagnostics_update: Task<()>,
 1044    inline_diagnostics_enabled: bool,
 1045    diagnostics_enabled: bool,
 1046    word_completions_enabled: bool,
 1047    inline_diagnostics: Vec<(Anchor, InlineDiagnostic)>,
 1048    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
 1049    hard_wrap: Option<usize>,
 1050    project: Option<Entity<Project>>,
 1051    semantics_provider: Option<Rc<dyn SemanticsProvider>>,
 1052    completion_provider: Option<Rc<dyn CompletionProvider>>,
 1053    collaboration_hub: Option<Box<dyn CollaborationHub>>,
 1054    blink_manager: Entity<BlinkManager>,
 1055    show_cursor_names: bool,
 1056    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
 1057    pub show_local_selections: bool,
 1058    mode: EditorMode,
 1059    show_breadcrumbs: bool,
 1060    show_gutter: bool,
 1061    show_scrollbars: ScrollbarAxes,
 1062    minimap_visibility: MinimapVisibility,
 1063    offset_content: bool,
 1064    disable_expand_excerpt_buttons: bool,
 1065    show_line_numbers: Option<bool>,
 1066    use_relative_line_numbers: Option<bool>,
 1067    show_git_diff_gutter: Option<bool>,
 1068    show_code_actions: Option<bool>,
 1069    show_runnables: Option<bool>,
 1070    show_breakpoints: Option<bool>,
 1071    show_wrap_guides: Option<bool>,
 1072    show_indent_guides: Option<bool>,
 1073    highlight_order: usize,
 1074    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
 1075    background_highlights: HashMap<HighlightKey, BackgroundHighlight>,
 1076    gutter_highlights: HashMap<TypeId, GutterHighlight>,
 1077    scrollbar_marker_state: ScrollbarMarkerState,
 1078    active_indent_guides_state: ActiveIndentGuidesState,
 1079    nav_history: Option<ItemNavHistory>,
 1080    context_menu: RefCell<Option<CodeContextMenu>>,
 1081    context_menu_options: Option<ContextMenuOptions>,
 1082    mouse_context_menu: Option<MouseContextMenu>,
 1083    completion_tasks: Vec<(CompletionId, Task<()>)>,
 1084    inline_blame_popover: Option<InlineBlamePopover>,
 1085    inline_blame_popover_show_task: Option<Task<()>>,
 1086    signature_help_state: SignatureHelpState,
 1087    auto_signature_help: Option<bool>,
 1088    find_all_references_task_sources: Vec<Anchor>,
 1089    next_completion_id: CompletionId,
 1090    available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
 1091    code_actions_task: Option<Task<Result<()>>>,
 1092    quick_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1093    debounced_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1094    document_highlights_task: Option<Task<()>>,
 1095    linked_editing_range_task: Option<Task<Option<()>>>,
 1096    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
 1097    pending_rename: Option<RenameState>,
 1098    searchable: bool,
 1099    cursor_shape: CursorShape,
 1100    current_line_highlight: Option<CurrentLineHighlight>,
 1101    autoindent_mode: Option<AutoindentMode>,
 1102    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
 1103    input_enabled: bool,
 1104    use_modal_editing: bool,
 1105    read_only: bool,
 1106    leader_id: Option<CollaboratorId>,
 1107    remote_id: Option<ViewId>,
 1108    pub hover_state: HoverState,
 1109    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
 1110    gutter_hovered: bool,
 1111    hovered_link_state: Option<HoveredLinkState>,
 1112    edit_prediction_provider: Option<RegisteredEditPredictionProvider>,
 1113    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
 1114    active_edit_prediction: Option<EditPredictionState>,
 1115    /// Used to prevent flickering as the user types while the menu is open
 1116    stale_edit_prediction_in_menu: Option<EditPredictionState>,
 1117    edit_prediction_settings: EditPredictionSettings,
 1118    edit_predictions_hidden_for_vim_mode: bool,
 1119    show_edit_predictions_override: Option<bool>,
 1120    menu_edit_predictions_policy: MenuEditPredictionsPolicy,
 1121    edit_prediction_preview: EditPredictionPreview,
 1122    edit_prediction_indent_conflict: bool,
 1123    edit_prediction_requires_modifier_in_indent_conflict: bool,
 1124    next_inlay_id: usize,
 1125    next_color_inlay_id: usize,
 1126    _subscriptions: Vec<Subscription>,
 1127    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
 1128    gutter_dimensions: GutterDimensions,
 1129    style: Option<EditorStyle>,
 1130    text_style_refinement: Option<TextStyleRefinement>,
 1131    next_editor_action_id: EditorActionId,
 1132    editor_actions: Rc<
 1133        RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&Editor, &mut Window, &mut Context<Self>)>>>,
 1134    >,
 1135    use_autoclose: bool,
 1136    use_auto_surround: bool,
 1137    auto_replace_emoji_shortcode: bool,
 1138    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1139    show_git_blame_gutter: bool,
 1140    show_git_blame_inline: bool,
 1141    show_git_blame_inline_delay_task: Option<Task<()>>,
 1142    git_blame_inline_enabled: bool,
 1143    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1144    buffer_serialization: Option<BufferSerialization>,
 1145    show_selection_menu: Option<bool>,
 1146    blame: Option<Entity<GitBlame>>,
 1147    blame_subscription: Option<Subscription>,
 1148    custom_context_menu: Option<
 1149        Box<
 1150            dyn 'static
 1151                + Fn(
 1152                    &mut Self,
 1153                    DisplayPoint,
 1154                    &mut Window,
 1155                    &mut Context<Self>,
 1156                ) -> Option<Entity<ui::ContextMenu>>,
 1157        >,
 1158    >,
 1159    last_bounds: Option<Bounds<Pixels>>,
 1160    last_position_map: Option<Rc<PositionMap>>,
 1161    expect_bounds_change: Option<Bounds<Pixels>>,
 1162    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
 1163    tasks_update_task: Option<Task<()>>,
 1164    breakpoint_store: Option<Entity<BreakpointStore>>,
 1165    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1166    hovered_diff_hunk_row: Option<DisplayRow>,
 1167    pull_diagnostics_task: Task<()>,
 1168    in_project_search: bool,
 1169    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1170    breadcrumb_header: Option<String>,
 1171    focused_block: Option<FocusedBlock>,
 1172    next_scroll_position: NextScrollCursorCenterTopBottom,
 1173    addons: HashMap<TypeId, Box<dyn Addon>>,
 1174    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1175    load_diff_task: Option<Shared<Task<()>>>,
 1176    /// Whether we are temporarily displaying a diff other than git's
 1177    temporary_diff_override: bool,
 1178    selection_mark_mode: bool,
 1179    toggle_fold_multiple_buffers: Task<()>,
 1180    _scroll_cursor_center_top_bottom_task: Task<()>,
 1181    serialize_selections: Task<()>,
 1182    serialize_folds: Task<()>,
 1183    mouse_cursor_hidden: bool,
 1184    minimap: Option<Entity<Self>>,
 1185    hide_mouse_mode: HideMouseMode,
 1186    pub change_list: ChangeList,
 1187    inline_value_cache: InlineValueCache,
 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    pub lookup_key: Option<Box<dyn Any + Send + Sync>>,
 1195    applicable_language_settings: HashMap<Option<LanguageName>, LanguageSettings>,
 1196    fetched_tree_sitter_chunks: HashMap<ExcerptId, HashSet<Range<BufferRow>>>,
 1197}
 1198
 1199fn debounce_value(debounce_ms: u64) -> Option<Duration> {
 1200    if debounce_ms > 0 {
 1201        Some(Duration::from_millis(debounce_ms))
 1202    } else {
 1203        None
 1204    }
 1205}
 1206
 1207#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1208enum NextScrollCursorCenterTopBottom {
 1209    #[default]
 1210    Center,
 1211    Top,
 1212    Bottom,
 1213}
 1214
 1215impl NextScrollCursorCenterTopBottom {
 1216    fn next(&self) -> Self {
 1217        match self {
 1218            Self::Center => Self::Top,
 1219            Self::Top => Self::Bottom,
 1220            Self::Bottom => Self::Center,
 1221        }
 1222    }
 1223}
 1224
 1225#[derive(Clone)]
 1226pub struct EditorSnapshot {
 1227    pub mode: EditorMode,
 1228    show_gutter: bool,
 1229    show_line_numbers: Option<bool>,
 1230    show_git_diff_gutter: Option<bool>,
 1231    show_code_actions: Option<bool>,
 1232    show_runnables: Option<bool>,
 1233    show_breakpoints: Option<bool>,
 1234    git_blame_gutter_max_author_length: Option<usize>,
 1235    pub display_snapshot: DisplaySnapshot,
 1236    pub placeholder_display_snapshot: Option<DisplaySnapshot>,
 1237    is_focused: bool,
 1238    scroll_anchor: ScrollAnchor,
 1239    ongoing_scroll: OngoingScroll,
 1240    current_line_highlight: CurrentLineHighlight,
 1241    gutter_hovered: bool,
 1242}
 1243
 1244#[derive(Default, Debug, Clone, Copy)]
 1245pub struct GutterDimensions {
 1246    pub left_padding: Pixels,
 1247    pub right_padding: Pixels,
 1248    pub width: Pixels,
 1249    pub margin: Pixels,
 1250    pub git_blame_entries_width: Option<Pixels>,
 1251}
 1252
 1253impl GutterDimensions {
 1254    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1255        Self {
 1256            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1257            ..Default::default()
 1258        }
 1259    }
 1260
 1261    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1262        -cx.text_system().descent(font_id, font_size)
 1263    }
 1264    /// The full width of the space taken up by the gutter.
 1265    pub fn full_width(&self) -> Pixels {
 1266        self.margin + self.width
 1267    }
 1268
 1269    /// The width of the space reserved for the fold indicators,
 1270    /// use alongside 'justify_end' and `gutter_width` to
 1271    /// right align content with the line numbers
 1272    pub fn fold_area_width(&self) -> Pixels {
 1273        self.margin + self.right_padding
 1274    }
 1275}
 1276
 1277struct CharacterDimensions {
 1278    em_width: Pixels,
 1279    em_advance: Pixels,
 1280    line_height: Pixels,
 1281}
 1282
 1283#[derive(Debug)]
 1284pub struct RemoteSelection {
 1285    pub replica_id: ReplicaId,
 1286    pub selection: Selection<Anchor>,
 1287    pub cursor_shape: CursorShape,
 1288    pub collaborator_id: CollaboratorId,
 1289    pub line_mode: bool,
 1290    pub user_name: Option<SharedString>,
 1291    pub color: PlayerColor,
 1292}
 1293
 1294#[derive(Clone, Debug)]
 1295struct SelectionHistoryEntry {
 1296    selections: Arc<[Selection<Anchor>]>,
 1297    select_next_state: Option<SelectNextState>,
 1298    select_prev_state: Option<SelectNextState>,
 1299    add_selections_state: Option<AddSelectionsState>,
 1300}
 1301
 1302#[derive(Copy, Clone, Debug, PartialEq, Eq)]
 1303enum SelectionHistoryMode {
 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
 1316impl Default for SelectionHistoryMode {
 1317    fn default() -> Self {
 1318        Self::Normal
 1319    }
 1320}
 1321
 1322#[derive(Debug)]
 1323/// SelectionEffects controls the side-effects of updating the selection.
 1324///
 1325/// The default behaviour does "what you mostly want":
 1326/// - it pushes to the nav history if the cursor moved by >10 lines
 1327/// - it re-triggers completion requests
 1328/// - it scrolls to fit
 1329///
 1330/// You might want to modify these behaviours. For example when doing a "jump"
 1331/// like go to definition, we always want to add to nav history; but when scrolling
 1332/// in vim mode we never do.
 1333///
 1334/// Similarly, you might want to disable scrolling if you don't want the viewport to
 1335/// move.
 1336#[derive(Clone)]
 1337pub struct SelectionEffects {
 1338    nav_history: Option<bool>,
 1339    completions: bool,
 1340    scroll: Option<Autoscroll>,
 1341}
 1342
 1343impl Default for SelectionEffects {
 1344    fn default() -> Self {
 1345        Self {
 1346            nav_history: None,
 1347            completions: true,
 1348            scroll: Some(Autoscroll::fit()),
 1349        }
 1350    }
 1351}
 1352impl SelectionEffects {
 1353    pub fn scroll(scroll: Autoscroll) -> Self {
 1354        Self {
 1355            scroll: Some(scroll),
 1356            ..Default::default()
 1357        }
 1358    }
 1359
 1360    pub fn no_scroll() -> Self {
 1361        Self {
 1362            scroll: None,
 1363            ..Default::default()
 1364        }
 1365    }
 1366
 1367    pub fn completions(self, completions: bool) -> Self {
 1368        Self {
 1369            completions,
 1370            ..self
 1371        }
 1372    }
 1373
 1374    pub fn nav_history(self, nav_history: bool) -> Self {
 1375        Self {
 1376            nav_history: Some(nav_history),
 1377            ..self
 1378        }
 1379    }
 1380}
 1381
 1382struct DeferredSelectionEffectsState {
 1383    changed: bool,
 1384    effects: SelectionEffects,
 1385    old_cursor_position: Anchor,
 1386    history_entry: SelectionHistoryEntry,
 1387}
 1388
 1389#[derive(Default)]
 1390struct SelectionHistory {
 1391    #[allow(clippy::type_complexity)]
 1392    selections_by_transaction:
 1393        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1394    mode: SelectionHistoryMode,
 1395    undo_stack: VecDeque<SelectionHistoryEntry>,
 1396    redo_stack: VecDeque<SelectionHistoryEntry>,
 1397}
 1398
 1399impl SelectionHistory {
 1400    #[track_caller]
 1401    fn insert_transaction(
 1402        &mut self,
 1403        transaction_id: TransactionId,
 1404        selections: Arc<[Selection<Anchor>]>,
 1405    ) {
 1406        if selections.is_empty() {
 1407            log::error!(
 1408                "SelectionHistory::insert_transaction called with empty selections. Caller: {}",
 1409                std::panic::Location::caller()
 1410            );
 1411            return;
 1412        }
 1413        self.selections_by_transaction
 1414            .insert(transaction_id, (selections, None));
 1415    }
 1416
 1417    #[allow(clippy::type_complexity)]
 1418    fn transaction(
 1419        &self,
 1420        transaction_id: TransactionId,
 1421    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1422        self.selections_by_transaction.get(&transaction_id)
 1423    }
 1424
 1425    #[allow(clippy::type_complexity)]
 1426    fn transaction_mut(
 1427        &mut self,
 1428        transaction_id: TransactionId,
 1429    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1430        self.selections_by_transaction.get_mut(&transaction_id)
 1431    }
 1432
 1433    fn push(&mut self, entry: SelectionHistoryEntry) {
 1434        if !entry.selections.is_empty() {
 1435            match self.mode {
 1436                SelectionHistoryMode::Normal => {
 1437                    self.push_undo(entry);
 1438                    self.redo_stack.clear();
 1439                }
 1440                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1441                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1442                SelectionHistoryMode::Skipping => {}
 1443            }
 1444        }
 1445    }
 1446
 1447    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1448        if self
 1449            .undo_stack
 1450            .back()
 1451            .is_none_or(|e| e.selections != entry.selections)
 1452        {
 1453            self.undo_stack.push_back(entry);
 1454            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1455                self.undo_stack.pop_front();
 1456            }
 1457        }
 1458    }
 1459
 1460    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1461        if self
 1462            .redo_stack
 1463            .back()
 1464            .is_none_or(|e| e.selections != entry.selections)
 1465        {
 1466            self.redo_stack.push_back(entry);
 1467            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1468                self.redo_stack.pop_front();
 1469            }
 1470        }
 1471    }
 1472}
 1473
 1474#[derive(Clone, Copy)]
 1475pub struct RowHighlightOptions {
 1476    pub autoscroll: bool,
 1477    pub include_gutter: bool,
 1478}
 1479
 1480impl Default for RowHighlightOptions {
 1481    fn default() -> Self {
 1482        Self {
 1483            autoscroll: Default::default(),
 1484            include_gutter: true,
 1485        }
 1486    }
 1487}
 1488
 1489struct RowHighlight {
 1490    index: usize,
 1491    range: Range<Anchor>,
 1492    color: Hsla,
 1493    options: RowHighlightOptions,
 1494    type_id: TypeId,
 1495}
 1496
 1497#[derive(Clone, Debug)]
 1498struct AddSelectionsState {
 1499    groups: Vec<AddSelectionsGroup>,
 1500}
 1501
 1502#[derive(Clone, Debug)]
 1503struct AddSelectionsGroup {
 1504    above: bool,
 1505    stack: Vec<usize>,
 1506}
 1507
 1508#[derive(Clone)]
 1509struct SelectNextState {
 1510    query: AhoCorasick,
 1511    wordwise: bool,
 1512    done: bool,
 1513}
 1514
 1515impl std::fmt::Debug for SelectNextState {
 1516    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1517        f.debug_struct(std::any::type_name::<Self>())
 1518            .field("wordwise", &self.wordwise)
 1519            .field("done", &self.done)
 1520            .finish()
 1521    }
 1522}
 1523
 1524#[derive(Debug)]
 1525struct AutocloseRegion {
 1526    selection_id: usize,
 1527    range: Range<Anchor>,
 1528    pair: BracketPair,
 1529}
 1530
 1531#[derive(Debug)]
 1532struct SnippetState {
 1533    ranges: Vec<Vec<Range<Anchor>>>,
 1534    active_index: usize,
 1535    choices: Vec<Option<Vec<String>>>,
 1536}
 1537
 1538#[doc(hidden)]
 1539pub struct RenameState {
 1540    pub range: Range<Anchor>,
 1541    pub old_name: Arc<str>,
 1542    pub editor: Entity<Editor>,
 1543    block_id: CustomBlockId,
 1544}
 1545
 1546struct InvalidationStack<T>(Vec<T>);
 1547
 1548struct RegisteredEditPredictionProvider {
 1549    provider: Arc<dyn EditPredictionProviderHandle>,
 1550    _subscription: Subscription,
 1551}
 1552
 1553#[derive(Debug, PartialEq, Eq)]
 1554pub struct ActiveDiagnosticGroup {
 1555    pub active_range: Range<Anchor>,
 1556    pub active_message: String,
 1557    pub group_id: usize,
 1558    pub blocks: HashSet<CustomBlockId>,
 1559}
 1560
 1561#[derive(Debug, PartialEq, Eq)]
 1562
 1563pub(crate) enum ActiveDiagnostic {
 1564    None,
 1565    All,
 1566    Group(ActiveDiagnosticGroup),
 1567}
 1568
 1569#[derive(Serialize, Deserialize, Clone, Debug)]
 1570pub struct ClipboardSelection {
 1571    /// The number of bytes in this selection.
 1572    pub len: usize,
 1573    /// Whether this was a full-line selection.
 1574    pub is_entire_line: bool,
 1575    /// The indentation of the first line when this content was originally copied.
 1576    pub first_line_indent: u32,
 1577}
 1578
 1579// selections, scroll behavior, was newest selection reversed
 1580type SelectSyntaxNodeHistoryState = (
 1581    Box<[Selection<usize>]>,
 1582    SelectSyntaxNodeScrollBehavior,
 1583    bool,
 1584);
 1585
 1586#[derive(Default)]
 1587struct SelectSyntaxNodeHistory {
 1588    stack: Vec<SelectSyntaxNodeHistoryState>,
 1589    // disable temporarily to allow changing selections without losing the stack
 1590    pub disable_clearing: bool,
 1591}
 1592
 1593impl SelectSyntaxNodeHistory {
 1594    pub fn try_clear(&mut self) {
 1595        if !self.disable_clearing {
 1596            self.stack.clear();
 1597        }
 1598    }
 1599
 1600    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1601        self.stack.push(selection);
 1602    }
 1603
 1604    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1605        self.stack.pop()
 1606    }
 1607}
 1608
 1609enum SelectSyntaxNodeScrollBehavior {
 1610    CursorTop,
 1611    FitSelection,
 1612    CursorBottom,
 1613}
 1614
 1615#[derive(Debug)]
 1616pub(crate) struct NavigationData {
 1617    cursor_anchor: Anchor,
 1618    cursor_position: Point,
 1619    scroll_anchor: ScrollAnchor,
 1620    scroll_top_row: u32,
 1621}
 1622
 1623#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1624pub enum GotoDefinitionKind {
 1625    Symbol,
 1626    Declaration,
 1627    Type,
 1628    Implementation,
 1629}
 1630
 1631pub enum FormatTarget {
 1632    Buffers(HashSet<Entity<Buffer>>),
 1633    Ranges(Vec<Range<MultiBufferPoint>>),
 1634}
 1635
 1636pub(crate) struct FocusedBlock {
 1637    id: BlockId,
 1638    focus_handle: WeakFocusHandle,
 1639}
 1640
 1641#[derive(Clone)]
 1642enum JumpData {
 1643    MultiBufferRow {
 1644        row: MultiBufferRow,
 1645        line_offset_from_top: u32,
 1646    },
 1647    MultiBufferPoint {
 1648        excerpt_id: ExcerptId,
 1649        position: Point,
 1650        anchor: text::Anchor,
 1651        line_offset_from_top: u32,
 1652    },
 1653}
 1654
 1655pub enum MultibufferSelectionMode {
 1656    First,
 1657    All,
 1658}
 1659
 1660#[derive(Clone, Copy, Debug, Default)]
 1661pub struct RewrapOptions {
 1662    pub override_language_settings: bool,
 1663    pub preserve_existing_whitespace: bool,
 1664}
 1665
 1666impl Editor {
 1667    pub fn single_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::SingleLine, buffer, None, window, cx)
 1671    }
 1672
 1673    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1674        let buffer = cx.new(|cx| Buffer::local("", cx));
 1675        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1676        Self::new(EditorMode::full(), buffer, None, window, cx)
 1677    }
 1678
 1679    pub fn auto_height(
 1680        min_lines: usize,
 1681        max_lines: usize,
 1682        window: &mut Window,
 1683        cx: &mut Context<Self>,
 1684    ) -> Self {
 1685        let buffer = cx.new(|cx| Buffer::local("", cx));
 1686        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1687        Self::new(
 1688            EditorMode::AutoHeight {
 1689                min_lines,
 1690                max_lines: Some(max_lines),
 1691            },
 1692            buffer,
 1693            None,
 1694            window,
 1695            cx,
 1696        )
 1697    }
 1698
 1699    /// Creates a new auto-height editor with a minimum number of lines but no maximum.
 1700    /// The editor grows as tall as needed to fit its content.
 1701    pub fn auto_height_unbounded(
 1702        min_lines: usize,
 1703        window: &mut Window,
 1704        cx: &mut Context<Self>,
 1705    ) -> Self {
 1706        let buffer = cx.new(|cx| Buffer::local("", cx));
 1707        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1708        Self::new(
 1709            EditorMode::AutoHeight {
 1710                min_lines,
 1711                max_lines: None,
 1712            },
 1713            buffer,
 1714            None,
 1715            window,
 1716            cx,
 1717        )
 1718    }
 1719
 1720    pub fn for_buffer(
 1721        buffer: Entity<Buffer>,
 1722        project: Option<Entity<Project>>,
 1723        window: &mut Window,
 1724        cx: &mut Context<Self>,
 1725    ) -> Self {
 1726        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1727        Self::new(EditorMode::full(), buffer, project, window, cx)
 1728    }
 1729
 1730    pub fn for_multibuffer(
 1731        buffer: Entity<MultiBuffer>,
 1732        project: Option<Entity<Project>>,
 1733        window: &mut Window,
 1734        cx: &mut Context<Self>,
 1735    ) -> Self {
 1736        Self::new(EditorMode::full(), buffer, project, window, cx)
 1737    }
 1738
 1739    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1740        let mut clone = Self::new(
 1741            self.mode.clone(),
 1742            self.buffer.clone(),
 1743            self.project.clone(),
 1744            window,
 1745            cx,
 1746        );
 1747        self.display_map.update(cx, |display_map, cx| {
 1748            let snapshot = display_map.snapshot(cx);
 1749            clone.display_map.update(cx, |display_map, cx| {
 1750                display_map.set_state(&snapshot, cx);
 1751            });
 1752        });
 1753        clone.folds_did_change(cx);
 1754        clone.selections.clone_state(&self.selections);
 1755        clone.scroll_manager.clone_state(&self.scroll_manager);
 1756        clone.searchable = self.searchable;
 1757        clone.read_only = self.read_only;
 1758        clone
 1759    }
 1760
 1761    pub fn new(
 1762        mode: EditorMode,
 1763        buffer: Entity<MultiBuffer>,
 1764        project: Option<Entity<Project>>,
 1765        window: &mut Window,
 1766        cx: &mut Context<Self>,
 1767    ) -> Self {
 1768        Editor::new_internal(mode, buffer, project, None, window, cx)
 1769    }
 1770
 1771    fn new_internal(
 1772        mode: EditorMode,
 1773        multi_buffer: Entity<MultiBuffer>,
 1774        project: Option<Entity<Project>>,
 1775        display_map: Option<Entity<DisplayMap>>,
 1776        window: &mut Window,
 1777        cx: &mut Context<Self>,
 1778    ) -> Self {
 1779        debug_assert!(
 1780            display_map.is_none() || mode.is_minimap(),
 1781            "Providing a display map for a new editor is only intended for the minimap and might have unintended side effects otherwise!"
 1782        );
 1783
 1784        let full_mode = mode.is_full();
 1785        let is_minimap = mode.is_minimap();
 1786        let diagnostics_max_severity = if full_mode {
 1787            EditorSettings::get_global(cx)
 1788                .diagnostics_max_severity
 1789                .unwrap_or(DiagnosticSeverity::Hint)
 1790        } else {
 1791            DiagnosticSeverity::Off
 1792        };
 1793        let style = window.text_style();
 1794        let font_size = style.font_size.to_pixels(window.rem_size());
 1795        let editor = cx.entity().downgrade();
 1796        let fold_placeholder = FoldPlaceholder {
 1797            constrain_width: false,
 1798            render: Arc::new(move |fold_id, fold_range, cx| {
 1799                let editor = editor.clone();
 1800                div()
 1801                    .id(fold_id)
 1802                    .bg(cx.theme().colors().ghost_element_background)
 1803                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1804                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1805                    .rounded_xs()
 1806                    .size_full()
 1807                    .cursor_pointer()
 1808                    .child("")
 1809                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1810                    .on_click(move |_, _window, cx| {
 1811                        editor
 1812                            .update(cx, |editor, cx| {
 1813                                editor.unfold_ranges(
 1814                                    &[fold_range.start..fold_range.end],
 1815                                    true,
 1816                                    false,
 1817                                    cx,
 1818                                );
 1819                                cx.stop_propagation();
 1820                            })
 1821                            .ok();
 1822                    })
 1823                    .into_any()
 1824            }),
 1825            merge_adjacent: true,
 1826            ..FoldPlaceholder::default()
 1827        };
 1828        let display_map = display_map.unwrap_or_else(|| {
 1829            cx.new(|cx| {
 1830                DisplayMap::new(
 1831                    multi_buffer.clone(),
 1832                    style.font(),
 1833                    font_size,
 1834                    None,
 1835                    FILE_HEADER_HEIGHT,
 1836                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1837                    fold_placeholder,
 1838                    diagnostics_max_severity,
 1839                    cx,
 1840                )
 1841            })
 1842        });
 1843
 1844        let selections = SelectionsCollection::new();
 1845
 1846        let blink_manager = cx.new(|cx| {
 1847            let mut blink_manager = BlinkManager::new(CURSOR_BLINK_INTERVAL, cx);
 1848            if is_minimap {
 1849                blink_manager.disable(cx);
 1850            }
 1851            blink_manager
 1852        });
 1853
 1854        let soft_wrap_mode_override =
 1855            matches!(mode, EditorMode::SingleLine).then(|| language_settings::SoftWrap::None);
 1856
 1857        let mut project_subscriptions = Vec::new();
 1858        if full_mode && let Some(project) = project.as_ref() {
 1859            project_subscriptions.push(cx.subscribe_in(
 1860                project,
 1861                window,
 1862                |editor, _, event, window, cx| match event {
 1863                    project::Event::RefreshCodeLens => {
 1864                        // we always query lens with actions, without storing them, always refreshing them
 1865                    }
 1866                    project::Event::RefreshInlayHints {
 1867                        server_id,
 1868                        request_id,
 1869                    } => {
 1870                        editor.refresh_inlay_hints(
 1871                            InlayHintRefreshReason::RefreshRequested {
 1872                                server_id: *server_id,
 1873                                request_id: *request_id,
 1874                            },
 1875                            cx,
 1876                        );
 1877                    }
 1878                    project::Event::LanguageServerRemoved(..) => {
 1879                        if editor.tasks_update_task.is_none() {
 1880                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1881                        }
 1882                        editor.registered_buffers.clear();
 1883                        editor.register_visible_buffers(cx);
 1884                    }
 1885                    project::Event::LanguageServerAdded(..) => {
 1886                        if editor.tasks_update_task.is_none() {
 1887                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1888                        }
 1889                    }
 1890                    project::Event::SnippetEdit(id, snippet_edits) => {
 1891                        if let Some(buffer) = editor.buffer.read(cx).buffer(*id) {
 1892                            let focus_handle = editor.focus_handle(cx);
 1893                            if focus_handle.is_focused(window) {
 1894                                let snapshot = buffer.read(cx).snapshot();
 1895                                for (range, snippet) in snippet_edits {
 1896                                    let editor_range =
 1897                                        language::range_from_lsp(*range).to_offset(&snapshot);
 1898                                    editor
 1899                                        .insert_snippet(
 1900                                            &[editor_range],
 1901                                            snippet.clone(),
 1902                                            window,
 1903                                            cx,
 1904                                        )
 1905                                        .ok();
 1906                                }
 1907                            }
 1908                        }
 1909                    }
 1910                    project::Event::LanguageServerBufferRegistered { buffer_id, .. } => {
 1911                        let buffer_id = *buffer_id;
 1912                        if editor.buffer().read(cx).buffer(buffer_id).is_some() {
 1913                            editor.register_buffer(buffer_id, cx);
 1914                            editor.update_lsp_data(Some(buffer_id), window, cx);
 1915                            editor.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
 1916                            refresh_linked_ranges(editor, window, cx);
 1917                            editor.refresh_code_actions(window, cx);
 1918                            editor.refresh_document_highlights(cx);
 1919                        }
 1920                    }
 1921
 1922                    project::Event::EntryRenamed(transaction, project_path, abs_path) => {
 1923                        let Some(workspace) = editor.workspace() else {
 1924                            return;
 1925                        };
 1926                        let Some(active_editor) = workspace.read(cx).active_item_as::<Self>(cx)
 1927                        else {
 1928                            return;
 1929                        };
 1930
 1931                        if active_editor.entity_id() == cx.entity_id() {
 1932                            let entity_id = cx.entity_id();
 1933                            workspace.update(cx, |this, cx| {
 1934                                this.panes_mut()
 1935                                    .iter_mut()
 1936                                    .filter(|pane| pane.entity_id() != entity_id)
 1937                                    .for_each(|p| {
 1938                                        p.update(cx, |pane, _| {
 1939                                            pane.nav_history_mut().rename_item(
 1940                                                entity_id,
 1941                                                project_path.clone(),
 1942                                                abs_path.clone().into(),
 1943                                            );
 1944                                        })
 1945                                    });
 1946                            });
 1947                            let edited_buffers_already_open = {
 1948                                let other_editors: Vec<Entity<Editor>> = workspace
 1949                                    .read(cx)
 1950                                    .panes()
 1951                                    .iter()
 1952                                    .flat_map(|pane| pane.read(cx).items_of_type::<Editor>())
 1953                                    .filter(|editor| editor.entity_id() != cx.entity_id())
 1954                                    .collect();
 1955
 1956                                transaction.0.keys().all(|buffer| {
 1957                                    other_editors.iter().any(|editor| {
 1958                                        let multi_buffer = editor.read(cx).buffer();
 1959                                        multi_buffer.read(cx).is_singleton()
 1960                                            && multi_buffer.read(cx).as_singleton().map_or(
 1961                                                false,
 1962                                                |singleton| {
 1963                                                    singleton.entity_id() == buffer.entity_id()
 1964                                                },
 1965                                            )
 1966                                    })
 1967                                })
 1968                            };
 1969                            if !edited_buffers_already_open {
 1970                                let workspace = workspace.downgrade();
 1971                                let transaction = transaction.clone();
 1972                                cx.defer_in(window, move |_, window, cx| {
 1973                                    cx.spawn_in(window, async move |editor, cx| {
 1974                                        Self::open_project_transaction(
 1975                                            &editor,
 1976                                            workspace,
 1977                                            transaction,
 1978                                            "Rename".to_string(),
 1979                                            cx,
 1980                                        )
 1981                                        .await
 1982                                        .ok()
 1983                                    })
 1984                                    .detach();
 1985                                });
 1986                            }
 1987                        }
 1988                    }
 1989
 1990                    _ => {}
 1991                },
 1992            ));
 1993            if let Some(task_inventory) = project
 1994                .read(cx)
 1995                .task_store()
 1996                .read(cx)
 1997                .task_inventory()
 1998                .cloned()
 1999            {
 2000                project_subscriptions.push(cx.observe_in(
 2001                    &task_inventory,
 2002                    window,
 2003                    |editor, _, window, cx| {
 2004                        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2005                    },
 2006                ));
 2007            };
 2008
 2009            project_subscriptions.push(cx.subscribe_in(
 2010                &project.read(cx).breakpoint_store(),
 2011                window,
 2012                |editor, _, event, window, cx| match event {
 2013                    BreakpointStoreEvent::ClearDebugLines => {
 2014                        editor.clear_row_highlights::<ActiveDebugLine>();
 2015                        editor.refresh_inline_values(cx);
 2016                    }
 2017                    BreakpointStoreEvent::SetDebugLine => {
 2018                        if editor.go_to_active_debug_line(window, cx) {
 2019                            cx.stop_propagation();
 2020                        }
 2021
 2022                        editor.refresh_inline_values(cx);
 2023                    }
 2024                    _ => {}
 2025                },
 2026            ));
 2027            let git_store = project.read(cx).git_store().clone();
 2028            let project = project.clone();
 2029            project_subscriptions.push(cx.subscribe(&git_store, move |this, _, event, cx| {
 2030                if let GitStoreEvent::RepositoryAdded = event {
 2031                    this.load_diff_task = Some(
 2032                        update_uncommitted_diff_for_buffer(
 2033                            cx.entity(),
 2034                            &project,
 2035                            this.buffer.read(cx).all_buffers(),
 2036                            this.buffer.clone(),
 2037                            cx,
 2038                        )
 2039                        .shared(),
 2040                    );
 2041                }
 2042            }));
 2043        }
 2044
 2045        let buffer_snapshot = multi_buffer.read(cx).snapshot(cx);
 2046
 2047        let inlay_hint_settings =
 2048            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 2049        let focus_handle = cx.focus_handle();
 2050        if !is_minimap {
 2051            cx.on_focus(&focus_handle, window, Self::handle_focus)
 2052                .detach();
 2053            cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 2054                .detach();
 2055            cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 2056                .detach();
 2057            cx.on_blur(&focus_handle, window, Self::handle_blur)
 2058                .detach();
 2059            cx.observe_pending_input(window, Self::observe_pending_input)
 2060                .detach();
 2061        }
 2062
 2063        let show_indent_guides =
 2064            if matches!(mode, EditorMode::SingleLine | EditorMode::Minimap { .. }) {
 2065                Some(false)
 2066            } else {
 2067                None
 2068            };
 2069
 2070        let breakpoint_store = match (&mode, project.as_ref()) {
 2071            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 2072            _ => None,
 2073        };
 2074
 2075        let mut code_action_providers = Vec::new();
 2076        let mut load_uncommitted_diff = None;
 2077        if let Some(project) = project.clone() {
 2078            load_uncommitted_diff = Some(
 2079                update_uncommitted_diff_for_buffer(
 2080                    cx.entity(),
 2081                    &project,
 2082                    multi_buffer.read(cx).all_buffers(),
 2083                    multi_buffer.clone(),
 2084                    cx,
 2085                )
 2086                .shared(),
 2087            );
 2088            code_action_providers.push(Rc::new(project) as Rc<_>);
 2089        }
 2090
 2091        let mut editor = Self {
 2092            focus_handle,
 2093            show_cursor_when_unfocused: false,
 2094            last_focused_descendant: None,
 2095            buffer: multi_buffer.clone(),
 2096            display_map: display_map.clone(),
 2097            placeholder_display_map: None,
 2098            selections,
 2099            scroll_manager: ScrollManager::new(cx),
 2100            columnar_selection_state: None,
 2101            add_selections_state: None,
 2102            select_next_state: None,
 2103            select_prev_state: None,
 2104            selection_history: SelectionHistory::default(),
 2105            defer_selection_effects: false,
 2106            deferred_selection_effects_state: None,
 2107            autoclose_regions: Vec::new(),
 2108            snippet_stack: InvalidationStack::default(),
 2109            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 2110            ime_transaction: None,
 2111            active_diagnostics: ActiveDiagnostic::None,
 2112            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 2113            inline_diagnostics_update: Task::ready(()),
 2114            inline_diagnostics: Vec::new(),
 2115            soft_wrap_mode_override,
 2116            diagnostics_max_severity,
 2117            hard_wrap: None,
 2118            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 2119            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 2120            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 2121            project,
 2122            blink_manager: blink_manager.clone(),
 2123            show_local_selections: true,
 2124            show_scrollbars: ScrollbarAxes {
 2125                horizontal: full_mode,
 2126                vertical: full_mode,
 2127            },
 2128            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 2129            offset_content: !matches!(mode, EditorMode::SingleLine),
 2130            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 2131            show_gutter: full_mode,
 2132            show_line_numbers: (!full_mode).then_some(false),
 2133            use_relative_line_numbers: None,
 2134            disable_expand_excerpt_buttons: !full_mode,
 2135            show_git_diff_gutter: None,
 2136            show_code_actions: None,
 2137            show_runnables: None,
 2138            show_breakpoints: None,
 2139            show_wrap_guides: None,
 2140            show_indent_guides,
 2141            highlight_order: 0,
 2142            highlighted_rows: HashMap::default(),
 2143            background_highlights: HashMap::default(),
 2144            gutter_highlights: HashMap::default(),
 2145            scrollbar_marker_state: ScrollbarMarkerState::default(),
 2146            active_indent_guides_state: ActiveIndentGuidesState::default(),
 2147            nav_history: None,
 2148            context_menu: RefCell::new(None),
 2149            context_menu_options: None,
 2150            mouse_context_menu: None,
 2151            completion_tasks: Vec::new(),
 2152            inline_blame_popover: None,
 2153            inline_blame_popover_show_task: None,
 2154            signature_help_state: SignatureHelpState::default(),
 2155            auto_signature_help: None,
 2156            find_all_references_task_sources: Vec::new(),
 2157            next_completion_id: 0,
 2158            next_inlay_id: 0,
 2159            code_action_providers,
 2160            available_code_actions: None,
 2161            code_actions_task: None,
 2162            quick_selection_highlight_task: None,
 2163            debounced_selection_highlight_task: None,
 2164            document_highlights_task: None,
 2165            linked_editing_range_task: None,
 2166            pending_rename: None,
 2167            searchable: !is_minimap,
 2168            cursor_shape: EditorSettings::get_global(cx)
 2169                .cursor_shape
 2170                .unwrap_or_default(),
 2171            current_line_highlight: None,
 2172            autoindent_mode: Some(AutoindentMode::EachLine),
 2173
 2174            workspace: None,
 2175            input_enabled: !is_minimap,
 2176            use_modal_editing: full_mode,
 2177            read_only: is_minimap,
 2178            use_autoclose: true,
 2179            use_auto_surround: true,
 2180            auto_replace_emoji_shortcode: false,
 2181            jsx_tag_auto_close_enabled_in_any_buffer: false,
 2182            leader_id: None,
 2183            remote_id: None,
 2184            hover_state: HoverState::default(),
 2185            pending_mouse_down: None,
 2186            hovered_link_state: None,
 2187            edit_prediction_provider: None,
 2188            active_edit_prediction: None,
 2189            stale_edit_prediction_in_menu: None,
 2190            edit_prediction_preview: EditPredictionPreview::Inactive {
 2191                released_too_fast: false,
 2192            },
 2193            inline_diagnostics_enabled: full_mode,
 2194            diagnostics_enabled: full_mode,
 2195            word_completions_enabled: full_mode,
 2196            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 2197            gutter_hovered: false,
 2198            pixel_position_of_newest_cursor: None,
 2199            last_bounds: None,
 2200            last_position_map: None,
 2201            expect_bounds_change: None,
 2202            gutter_dimensions: GutterDimensions::default(),
 2203            style: None,
 2204            show_cursor_names: false,
 2205            hovered_cursors: HashMap::default(),
 2206            next_editor_action_id: EditorActionId::default(),
 2207            editor_actions: Rc::default(),
 2208            edit_predictions_hidden_for_vim_mode: false,
 2209            show_edit_predictions_override: None,
 2210            menu_edit_predictions_policy: MenuEditPredictionsPolicy::ByProvider,
 2211            edit_prediction_settings: EditPredictionSettings::Disabled,
 2212            edit_prediction_indent_conflict: false,
 2213            edit_prediction_requires_modifier_in_indent_conflict: true,
 2214            custom_context_menu: None,
 2215            show_git_blame_gutter: false,
 2216            show_git_blame_inline: false,
 2217            show_selection_menu: None,
 2218            show_git_blame_inline_delay_task: None,
 2219            git_blame_inline_enabled: full_mode
 2220                && ProjectSettings::get_global(cx).git.inline_blame.enabled,
 2221            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 2222            buffer_serialization: is_minimap.not().then(|| {
 2223                BufferSerialization::new(
 2224                    ProjectSettings::get_global(cx)
 2225                        .session
 2226                        .restore_unsaved_buffers,
 2227                )
 2228            }),
 2229            blame: None,
 2230            blame_subscription: None,
 2231            tasks: BTreeMap::default(),
 2232
 2233            breakpoint_store,
 2234            gutter_breakpoint_indicator: (None, None),
 2235            hovered_diff_hunk_row: None,
 2236            _subscriptions: (!is_minimap)
 2237                .then(|| {
 2238                    vec![
 2239                        cx.observe(&multi_buffer, Self::on_buffer_changed),
 2240                        cx.subscribe_in(&multi_buffer, window, Self::on_buffer_event),
 2241                        cx.observe_in(&display_map, window, Self::on_display_map_changed),
 2242                        cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 2243                        cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 2244                        observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 2245                        cx.observe_window_activation(window, |editor, window, cx| {
 2246                            let active = window.is_window_active();
 2247                            editor.blink_manager.update(cx, |blink_manager, cx| {
 2248                                if active {
 2249                                    blink_manager.enable(cx);
 2250                                } else {
 2251                                    blink_manager.disable(cx);
 2252                                }
 2253                            });
 2254                            if active {
 2255                                editor.show_mouse_cursor(cx);
 2256                            }
 2257                        }),
 2258                    ]
 2259                })
 2260                .unwrap_or_default(),
 2261            tasks_update_task: None,
 2262            pull_diagnostics_task: Task::ready(()),
 2263            colors: None,
 2264            refresh_colors_task: Task::ready(()),
 2265            inlay_hints: None,
 2266            next_color_inlay_id: 0,
 2267            post_scroll_update: Task::ready(()),
 2268            linked_edit_ranges: Default::default(),
 2269            in_project_search: false,
 2270            previous_search_ranges: None,
 2271            breadcrumb_header: None,
 2272            focused_block: None,
 2273            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 2274            addons: HashMap::default(),
 2275            registered_buffers: HashMap::default(),
 2276            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 2277            selection_mark_mode: false,
 2278            toggle_fold_multiple_buffers: Task::ready(()),
 2279            serialize_selections: Task::ready(()),
 2280            serialize_folds: Task::ready(()),
 2281            text_style_refinement: None,
 2282            load_diff_task: load_uncommitted_diff,
 2283            temporary_diff_override: false,
 2284            mouse_cursor_hidden: false,
 2285            minimap: None,
 2286            hide_mouse_mode: EditorSettings::get_global(cx)
 2287                .hide_mouse
 2288                .unwrap_or_default(),
 2289            change_list: ChangeList::new(),
 2290            mode,
 2291            selection_drag_state: SelectionDragState::None,
 2292            folding_newlines: Task::ready(()),
 2293            lookup_key: None,
 2294            applicable_language_settings: HashMap::default(),
 2295            fetched_tree_sitter_chunks: HashMap::default(),
 2296        };
 2297
 2298        if is_minimap {
 2299            return editor;
 2300        }
 2301
 2302        editor.applicable_language_settings = editor.fetch_applicable_language_settings(cx);
 2303
 2304        if let Some(breakpoints) = editor.breakpoint_store.as_ref() {
 2305            editor
 2306                ._subscriptions
 2307                .push(cx.observe(breakpoints, |_, _, cx| {
 2308                    cx.notify();
 2309                }));
 2310        }
 2311        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2312        editor._subscriptions.extend(project_subscriptions);
 2313
 2314        editor._subscriptions.push(cx.subscribe_in(
 2315            &cx.entity(),
 2316            window,
 2317            |editor, _, e: &EditorEvent, window, cx| match e {
 2318                EditorEvent::ScrollPositionChanged { local, .. } => {
 2319                    if *local {
 2320                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 2321                        editor.inline_blame_popover.take();
 2322                        let new_anchor = editor.scroll_manager.anchor();
 2323                        let snapshot = editor.snapshot(window, cx);
 2324                        editor.update_restoration_data(cx, move |data| {
 2325                            data.scroll_position = (
 2326                                new_anchor.top_row(snapshot.buffer_snapshot()),
 2327                                new_anchor.offset,
 2328                            );
 2329                        });
 2330
 2331                        editor.post_scroll_update = cx.spawn_in(window, async move |editor, cx| {
 2332                            cx.background_executor()
 2333                                .timer(Duration::from_millis(50))
 2334                                .await;
 2335                            editor
 2336                                .update_in(cx, |editor, window, cx| {
 2337                                    editor.register_visible_buffers(cx);
 2338                                    editor.refresh_colors_for_visible_range(None, window, cx);
 2339                                    editor.refresh_inlay_hints(
 2340                                        InlayHintRefreshReason::NewLinesShown,
 2341                                        cx,
 2342                                    );
 2343                                })
 2344                                .ok();
 2345                        });
 2346                    }
 2347                    editor.post_scroll_update = cx.spawn_in(window, async move |editor, cx| {
 2348                        cx.background_executor()
 2349                            .timer(Duration::from_millis(50))
 2350                            .await;
 2351                        editor
 2352                            .update_in(cx, |editor, window, cx| {
 2353                                editor.register_visible_buffers(cx);
 2354                                editor.refresh_colors_for_visible_range(None, window, cx);
 2355                                editor
 2356                                    .refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
 2357                                editor.colorize_brackets(false, cx);
 2358                            })
 2359                            .ok();
 2360                    });
 2361                }
 2362                EditorEvent::Edited { .. } => {
 2363                    if vim_flavor(cx).is_none() {
 2364                        let display_map = editor.display_snapshot(cx);
 2365                        let selections = editor.selections.all_adjusted_display(&display_map);
 2366                        let pop_state = editor
 2367                            .change_list
 2368                            .last()
 2369                            .map(|previous| {
 2370                                previous.len() == selections.len()
 2371                                    && previous.iter().enumerate().all(|(ix, p)| {
 2372                                        p.to_display_point(&display_map).row()
 2373                                            == selections[ix].head().row()
 2374                                    })
 2375                            })
 2376                            .unwrap_or(false);
 2377                        let new_positions = selections
 2378                            .into_iter()
 2379                            .map(|s| display_map.display_point_to_anchor(s.head(), Bias::Left))
 2380                            .collect();
 2381                        editor
 2382                            .change_list
 2383                            .push_to_change_list(pop_state, new_positions);
 2384                    }
 2385                }
 2386                _ => (),
 2387            },
 2388        ));
 2389
 2390        if let Some(dap_store) = editor
 2391            .project
 2392            .as_ref()
 2393            .map(|project| project.read(cx).dap_store())
 2394        {
 2395            let weak_editor = cx.weak_entity();
 2396
 2397            editor
 2398                ._subscriptions
 2399                .push(
 2400                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2401                        let session_entity = cx.entity();
 2402                        weak_editor
 2403                            .update(cx, |editor, cx| {
 2404                                editor._subscriptions.push(
 2405                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2406                                );
 2407                            })
 2408                            .ok();
 2409                    }),
 2410                );
 2411
 2412            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2413                editor
 2414                    ._subscriptions
 2415                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2416            }
 2417        }
 2418
 2419        // skip adding the initial selection to selection history
 2420        editor.selection_history.mode = SelectionHistoryMode::Skipping;
 2421        editor.end_selection(window, cx);
 2422        editor.selection_history.mode = SelectionHistoryMode::Normal;
 2423
 2424        editor.scroll_manager.show_scrollbars(window, cx);
 2425        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut editor, &multi_buffer, cx);
 2426
 2427        if full_mode {
 2428            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2429            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2430
 2431            if editor.git_blame_inline_enabled {
 2432                editor.start_git_blame_inline(false, window, cx);
 2433            }
 2434
 2435            editor.go_to_active_debug_line(window, cx);
 2436
 2437            editor.minimap =
 2438                editor.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2439            editor.colors = Some(LspColorData::new(cx));
 2440            editor.inlay_hints = Some(LspInlayHintData::new(inlay_hint_settings));
 2441
 2442            if let Some(buffer) = multi_buffer.read(cx).as_singleton() {
 2443                editor.register_buffer(buffer.read(cx).remote_id(), cx);
 2444            }
 2445            editor.update_lsp_data(None, window, cx);
 2446            editor.report_editor_event(ReportEditorEvent::EditorOpened, None, cx);
 2447        }
 2448
 2449        editor
 2450    }
 2451
 2452    pub fn display_snapshot(&self, cx: &mut App) -> DisplaySnapshot {
 2453        self.display_map.update(cx, |map, cx| map.snapshot(cx))
 2454    }
 2455
 2456    pub fn deploy_mouse_context_menu(
 2457        &mut self,
 2458        position: gpui::Point<Pixels>,
 2459        context_menu: Entity<ContextMenu>,
 2460        window: &mut Window,
 2461        cx: &mut Context<Self>,
 2462    ) {
 2463        self.mouse_context_menu = Some(MouseContextMenu::new(
 2464            self,
 2465            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2466            context_menu,
 2467            window,
 2468            cx,
 2469        ));
 2470    }
 2471
 2472    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2473        self.mouse_context_menu
 2474            .as_ref()
 2475            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2476    }
 2477
 2478    pub fn is_range_selected(&mut self, range: &Range<Anchor>, cx: &mut Context<Self>) -> bool {
 2479        if self
 2480            .selections
 2481            .pending_anchor()
 2482            .is_some_and(|pending_selection| {
 2483                let snapshot = self.buffer().read(cx).snapshot(cx);
 2484                pending_selection.range().includes(range, &snapshot)
 2485            })
 2486        {
 2487            return true;
 2488        }
 2489
 2490        self.selections
 2491            .disjoint_in_range::<usize>(range.clone(), &self.display_snapshot(cx))
 2492            .into_iter()
 2493            .any(|selection| {
 2494                // This is needed to cover a corner case, if we just check for an existing
 2495                // selection in the fold range, having a cursor at the start of the fold
 2496                // marks it as selected. Non-empty selections don't cause this.
 2497                let length = selection.end - selection.start;
 2498                length > 0
 2499            })
 2500    }
 2501
 2502    pub fn key_context(&self, window: &mut Window, cx: &mut App) -> KeyContext {
 2503        self.key_context_internal(self.has_active_edit_prediction(), window, cx)
 2504    }
 2505
 2506    fn key_context_internal(
 2507        &self,
 2508        has_active_edit_prediction: bool,
 2509        window: &mut Window,
 2510        cx: &mut App,
 2511    ) -> KeyContext {
 2512        let mut key_context = KeyContext::new_with_defaults();
 2513        key_context.add("Editor");
 2514        let mode = match self.mode {
 2515            EditorMode::SingleLine => "single_line",
 2516            EditorMode::AutoHeight { .. } => "auto_height",
 2517            EditorMode::Minimap { .. } => "minimap",
 2518            EditorMode::Full { .. } => "full",
 2519        };
 2520
 2521        if EditorSettings::jupyter_enabled(cx) {
 2522            key_context.add("jupyter");
 2523        }
 2524
 2525        key_context.set("mode", mode);
 2526        if self.pending_rename.is_some() {
 2527            key_context.add("renaming");
 2528        }
 2529
 2530        if let Some(snippet_stack) = self.snippet_stack.last() {
 2531            key_context.add("in_snippet");
 2532
 2533            if snippet_stack.active_index > 0 {
 2534                key_context.add("has_previous_tabstop");
 2535            }
 2536
 2537            if snippet_stack.active_index < snippet_stack.ranges.len().saturating_sub(1) {
 2538                key_context.add("has_next_tabstop");
 2539            }
 2540        }
 2541
 2542        match self.context_menu.borrow().as_ref() {
 2543            Some(CodeContextMenu::Completions(menu)) => {
 2544                if menu.visible() {
 2545                    key_context.add("menu");
 2546                    key_context.add("showing_completions");
 2547                }
 2548            }
 2549            Some(CodeContextMenu::CodeActions(menu)) => {
 2550                if menu.visible() {
 2551                    key_context.add("menu");
 2552                    key_context.add("showing_code_actions")
 2553                }
 2554            }
 2555            None => {}
 2556        }
 2557
 2558        if self.signature_help_state.has_multiple_signatures() {
 2559            key_context.add("showing_signature_help");
 2560        }
 2561
 2562        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2563        if !self.focus_handle(cx).contains_focused(window, cx)
 2564            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2565        {
 2566            for addon in self.addons.values() {
 2567                addon.extend_key_context(&mut key_context, cx)
 2568            }
 2569        }
 2570
 2571        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2572            if let Some(extension) = singleton_buffer.read(cx).file().and_then(|file| {
 2573                Some(
 2574                    file.full_path(cx)
 2575                        .extension()?
 2576                        .to_string_lossy()
 2577                        .into_owned(),
 2578                )
 2579            }) {
 2580                key_context.set("extension", extension);
 2581            }
 2582        } else {
 2583            key_context.add("multibuffer");
 2584        }
 2585
 2586        if has_active_edit_prediction {
 2587            if self.edit_prediction_in_conflict() {
 2588                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2589            } else {
 2590                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2591                key_context.add("copilot_suggestion");
 2592            }
 2593        }
 2594
 2595        if self.selection_mark_mode {
 2596            key_context.add("selection_mode");
 2597        }
 2598
 2599        let disjoint = self.selections.disjoint_anchors();
 2600        let snapshot = self.snapshot(window, cx);
 2601        let snapshot = snapshot.buffer_snapshot();
 2602        if self.mode == EditorMode::SingleLine
 2603            && let [selection] = disjoint
 2604            && selection.start == selection.end
 2605            && selection.end.to_offset(snapshot) == snapshot.len()
 2606        {
 2607            key_context.add("end_of_input");
 2608        }
 2609
 2610        key_context
 2611    }
 2612
 2613    pub fn last_bounds(&self) -> Option<&Bounds<Pixels>> {
 2614        self.last_bounds.as_ref()
 2615    }
 2616
 2617    fn show_mouse_cursor(&mut self, cx: &mut Context<Self>) {
 2618        if self.mouse_cursor_hidden {
 2619            self.mouse_cursor_hidden = false;
 2620            cx.notify();
 2621        }
 2622    }
 2623
 2624    pub fn hide_mouse_cursor(&mut self, origin: HideMouseCursorOrigin, cx: &mut Context<Self>) {
 2625        let hide_mouse_cursor = match origin {
 2626            HideMouseCursorOrigin::TypingAction => {
 2627                matches!(
 2628                    self.hide_mouse_mode,
 2629                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2630                )
 2631            }
 2632            HideMouseCursorOrigin::MovementAction => {
 2633                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2634            }
 2635        };
 2636        if self.mouse_cursor_hidden != hide_mouse_cursor {
 2637            self.mouse_cursor_hidden = hide_mouse_cursor;
 2638            cx.notify();
 2639        }
 2640    }
 2641
 2642    pub fn edit_prediction_in_conflict(&self) -> bool {
 2643        if !self.show_edit_predictions_in_menu() {
 2644            return false;
 2645        }
 2646
 2647        let showing_completions = self
 2648            .context_menu
 2649            .borrow()
 2650            .as_ref()
 2651            .is_some_and(|context| matches!(context, CodeContextMenu::Completions(_)));
 2652
 2653        showing_completions
 2654            || self.edit_prediction_requires_modifier()
 2655            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2656            // bindings to insert tab characters.
 2657            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2658    }
 2659
 2660    pub fn accept_edit_prediction_keybind(
 2661        &self,
 2662        accept_partial: bool,
 2663        window: &mut Window,
 2664        cx: &mut App,
 2665    ) -> AcceptEditPredictionBinding {
 2666        let key_context = self.key_context_internal(true, window, cx);
 2667        let in_conflict = self.edit_prediction_in_conflict();
 2668
 2669        let bindings = if accept_partial {
 2670            window.bindings_for_action_in_context(&AcceptPartialEditPrediction, key_context)
 2671        } else {
 2672            window.bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2673        };
 2674
 2675        // TODO: if the binding contains multiple keystrokes, display all of them, not
 2676        // just the first one.
 2677        AcceptEditPredictionBinding(bindings.into_iter().rev().find(|binding| {
 2678            !in_conflict
 2679                || binding
 2680                    .keystrokes()
 2681                    .first()
 2682                    .is_some_and(|keystroke| keystroke.modifiers().modified())
 2683        }))
 2684    }
 2685
 2686    pub fn new_file(
 2687        workspace: &mut Workspace,
 2688        _: &workspace::NewFile,
 2689        window: &mut Window,
 2690        cx: &mut Context<Workspace>,
 2691    ) {
 2692        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2693            "Failed to create buffer",
 2694            window,
 2695            cx,
 2696            |e, _, _| match e.error_code() {
 2697                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2698                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2699                e.error_tag("required").unwrap_or("the latest version")
 2700            )),
 2701                _ => None,
 2702            },
 2703        );
 2704    }
 2705
 2706    pub fn new_in_workspace(
 2707        workspace: &mut Workspace,
 2708        window: &mut Window,
 2709        cx: &mut Context<Workspace>,
 2710    ) -> Task<Result<Entity<Editor>>> {
 2711        let project = workspace.project().clone();
 2712        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2713
 2714        cx.spawn_in(window, async move |workspace, cx| {
 2715            let buffer = create.await?;
 2716            workspace.update_in(cx, |workspace, window, cx| {
 2717                let editor =
 2718                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2719                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2720                editor
 2721            })
 2722        })
 2723    }
 2724
 2725    fn new_file_vertical(
 2726        workspace: &mut Workspace,
 2727        _: &workspace::NewFileSplitVertical,
 2728        window: &mut Window,
 2729        cx: &mut Context<Workspace>,
 2730    ) {
 2731        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2732    }
 2733
 2734    fn new_file_horizontal(
 2735        workspace: &mut Workspace,
 2736        _: &workspace::NewFileSplitHorizontal,
 2737        window: &mut Window,
 2738        cx: &mut Context<Workspace>,
 2739    ) {
 2740        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2741    }
 2742
 2743    fn new_file_split(
 2744        workspace: &mut Workspace,
 2745        action: &workspace::NewFileSplit,
 2746        window: &mut Window,
 2747        cx: &mut Context<Workspace>,
 2748    ) {
 2749        Self::new_file_in_direction(workspace, action.0, window, cx)
 2750    }
 2751
 2752    fn new_file_in_direction(
 2753        workspace: &mut Workspace,
 2754        direction: SplitDirection,
 2755        window: &mut Window,
 2756        cx: &mut Context<Workspace>,
 2757    ) {
 2758        let project = workspace.project().clone();
 2759        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2760
 2761        cx.spawn_in(window, async move |workspace, cx| {
 2762            let buffer = create.await?;
 2763            workspace.update_in(cx, move |workspace, window, cx| {
 2764                workspace.split_item(
 2765                    direction,
 2766                    Box::new(
 2767                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2768                    ),
 2769                    window,
 2770                    cx,
 2771                )
 2772            })?;
 2773            anyhow::Ok(())
 2774        })
 2775        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2776            match e.error_code() {
 2777                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2778                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2779                e.error_tag("required").unwrap_or("the latest version")
 2780            )),
 2781                _ => None,
 2782            }
 2783        });
 2784    }
 2785
 2786    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2787        self.leader_id
 2788    }
 2789
 2790    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2791        &self.buffer
 2792    }
 2793
 2794    pub fn project(&self) -> Option<&Entity<Project>> {
 2795        self.project.as_ref()
 2796    }
 2797
 2798    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2799        self.workspace.as_ref()?.0.upgrade()
 2800    }
 2801
 2802    /// Returns the workspace serialization ID if this editor should be serialized.
 2803    fn workspace_serialization_id(&self, _cx: &App) -> Option<WorkspaceId> {
 2804        self.workspace
 2805            .as_ref()
 2806            .filter(|_| self.should_serialize_buffer())
 2807            .and_then(|workspace| workspace.1)
 2808    }
 2809
 2810    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2811        self.buffer().read(cx).title(cx)
 2812    }
 2813
 2814    pub fn snapshot(&self, window: &Window, cx: &mut App) -> EditorSnapshot {
 2815        let git_blame_gutter_max_author_length = self
 2816            .render_git_blame_gutter(cx)
 2817            .then(|| {
 2818                if let Some(blame) = self.blame.as_ref() {
 2819                    let max_author_length =
 2820                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2821                    Some(max_author_length)
 2822                } else {
 2823                    None
 2824                }
 2825            })
 2826            .flatten();
 2827
 2828        EditorSnapshot {
 2829            mode: self.mode.clone(),
 2830            show_gutter: self.show_gutter,
 2831            show_line_numbers: self.show_line_numbers,
 2832            show_git_diff_gutter: self.show_git_diff_gutter,
 2833            show_code_actions: self.show_code_actions,
 2834            show_runnables: self.show_runnables,
 2835            show_breakpoints: self.show_breakpoints,
 2836            git_blame_gutter_max_author_length,
 2837            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2838            placeholder_display_snapshot: self
 2839                .placeholder_display_map
 2840                .as_ref()
 2841                .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx))),
 2842            scroll_anchor: self.scroll_manager.anchor(),
 2843            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2844            is_focused: self.focus_handle.is_focused(window),
 2845            current_line_highlight: self
 2846                .current_line_highlight
 2847                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2848            gutter_hovered: self.gutter_hovered,
 2849        }
 2850    }
 2851
 2852    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2853        self.buffer.read(cx).language_at(point, cx)
 2854    }
 2855
 2856    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2857        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2858    }
 2859
 2860    pub fn active_excerpt(
 2861        &self,
 2862        cx: &App,
 2863    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2864        self.buffer
 2865            .read(cx)
 2866            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2867    }
 2868
 2869    pub fn mode(&self) -> &EditorMode {
 2870        &self.mode
 2871    }
 2872
 2873    pub fn set_mode(&mut self, mode: EditorMode) {
 2874        self.mode = mode;
 2875    }
 2876
 2877    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2878        self.collaboration_hub.as_deref()
 2879    }
 2880
 2881    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2882        self.collaboration_hub = Some(hub);
 2883    }
 2884
 2885    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2886        self.in_project_search = in_project_search;
 2887    }
 2888
 2889    pub fn set_custom_context_menu(
 2890        &mut self,
 2891        f: impl 'static
 2892        + Fn(
 2893            &mut Self,
 2894            DisplayPoint,
 2895            &mut Window,
 2896            &mut Context<Self>,
 2897        ) -> Option<Entity<ui::ContextMenu>>,
 2898    ) {
 2899        self.custom_context_menu = Some(Box::new(f))
 2900    }
 2901
 2902    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 2903        self.completion_provider = provider;
 2904    }
 2905
 2906    #[cfg(any(test, feature = "test-support"))]
 2907    pub fn completion_provider(&self) -> Option<Rc<dyn CompletionProvider>> {
 2908        self.completion_provider.clone()
 2909    }
 2910
 2911    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 2912        self.semantics_provider.clone()
 2913    }
 2914
 2915    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 2916        self.semantics_provider = provider;
 2917    }
 2918
 2919    pub fn set_edit_prediction_provider<T>(
 2920        &mut self,
 2921        provider: Option<Entity<T>>,
 2922        window: &mut Window,
 2923        cx: &mut Context<Self>,
 2924    ) where
 2925        T: EditPredictionProvider,
 2926    {
 2927        self.edit_prediction_provider = provider.map(|provider| RegisteredEditPredictionProvider {
 2928            _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 2929                if this.focus_handle.is_focused(window) {
 2930                    this.update_visible_edit_prediction(window, cx);
 2931                }
 2932            }),
 2933            provider: Arc::new(provider),
 2934        });
 2935        self.update_edit_prediction_settings(cx);
 2936        self.refresh_edit_prediction(false, false, window, cx);
 2937    }
 2938
 2939    pub fn placeholder_text(&self, cx: &mut App) -> Option<String> {
 2940        self.placeholder_display_map
 2941            .as_ref()
 2942            .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx)).text())
 2943    }
 2944
 2945    pub fn set_placeholder_text(
 2946        &mut self,
 2947        placeholder_text: &str,
 2948        window: &mut Window,
 2949        cx: &mut Context<Self>,
 2950    ) {
 2951        let multibuffer = cx
 2952            .new(|cx| MultiBuffer::singleton(cx.new(|cx| Buffer::local(placeholder_text, cx)), cx));
 2953
 2954        let style = window.text_style();
 2955
 2956        self.placeholder_display_map = Some(cx.new(|cx| {
 2957            DisplayMap::new(
 2958                multibuffer,
 2959                style.font(),
 2960                style.font_size.to_pixels(window.rem_size()),
 2961                None,
 2962                FILE_HEADER_HEIGHT,
 2963                MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 2964                Default::default(),
 2965                DiagnosticSeverity::Off,
 2966                cx,
 2967            )
 2968        }));
 2969        cx.notify();
 2970    }
 2971
 2972    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 2973        self.cursor_shape = cursor_shape;
 2974
 2975        // Disrupt blink for immediate user feedback that the cursor shape has changed
 2976        self.blink_manager.update(cx, BlinkManager::show_cursor);
 2977
 2978        cx.notify();
 2979    }
 2980
 2981    pub fn set_current_line_highlight(
 2982        &mut self,
 2983        current_line_highlight: Option<CurrentLineHighlight>,
 2984    ) {
 2985        self.current_line_highlight = current_line_highlight;
 2986    }
 2987
 2988    pub fn range_for_match<T: std::marker::Copy>(
 2989        &self,
 2990        range: &Range<T>,
 2991        collapse: bool,
 2992    ) -> Range<T> {
 2993        if collapse {
 2994            return range.start..range.start;
 2995        }
 2996        range.clone()
 2997    }
 2998
 2999    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 3000        if self.display_map.read(cx).clip_at_line_ends != clip {
 3001            self.display_map
 3002                .update(cx, |map, _| map.clip_at_line_ends = clip);
 3003        }
 3004    }
 3005
 3006    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 3007        self.input_enabled = input_enabled;
 3008    }
 3009
 3010    pub fn set_edit_predictions_hidden_for_vim_mode(
 3011        &mut self,
 3012        hidden: bool,
 3013        window: &mut Window,
 3014        cx: &mut Context<Self>,
 3015    ) {
 3016        if hidden != self.edit_predictions_hidden_for_vim_mode {
 3017            self.edit_predictions_hidden_for_vim_mode = hidden;
 3018            if hidden {
 3019                self.update_visible_edit_prediction(window, cx);
 3020            } else {
 3021                self.refresh_edit_prediction(true, false, window, cx);
 3022            }
 3023        }
 3024    }
 3025
 3026    pub fn set_menu_edit_predictions_policy(&mut self, value: MenuEditPredictionsPolicy) {
 3027        self.menu_edit_predictions_policy = value;
 3028    }
 3029
 3030    pub fn set_autoindent(&mut self, autoindent: bool) {
 3031        if autoindent {
 3032            self.autoindent_mode = Some(AutoindentMode::EachLine);
 3033        } else {
 3034            self.autoindent_mode = None;
 3035        }
 3036    }
 3037
 3038    pub fn read_only(&self, cx: &App) -> bool {
 3039        self.read_only || self.buffer.read(cx).read_only()
 3040    }
 3041
 3042    pub fn set_read_only(&mut self, read_only: bool) {
 3043        self.read_only = read_only;
 3044    }
 3045
 3046    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 3047        self.use_autoclose = autoclose;
 3048    }
 3049
 3050    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 3051        self.use_auto_surround = auto_surround;
 3052    }
 3053
 3054    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 3055        self.auto_replace_emoji_shortcode = auto_replace;
 3056    }
 3057
 3058    pub fn set_should_serialize(&mut self, should_serialize: bool, cx: &App) {
 3059        self.buffer_serialization = should_serialize.then(|| {
 3060            BufferSerialization::new(
 3061                ProjectSettings::get_global(cx)
 3062                    .session
 3063                    .restore_unsaved_buffers,
 3064            )
 3065        })
 3066    }
 3067
 3068    fn should_serialize_buffer(&self) -> bool {
 3069        self.buffer_serialization.is_some()
 3070    }
 3071
 3072    pub fn toggle_edit_predictions(
 3073        &mut self,
 3074        _: &ToggleEditPrediction,
 3075        window: &mut Window,
 3076        cx: &mut Context<Self>,
 3077    ) {
 3078        if self.show_edit_predictions_override.is_some() {
 3079            self.set_show_edit_predictions(None, window, cx);
 3080        } else {
 3081            let show_edit_predictions = !self.edit_predictions_enabled();
 3082            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 3083        }
 3084    }
 3085
 3086    pub fn set_show_edit_predictions(
 3087        &mut self,
 3088        show_edit_predictions: Option<bool>,
 3089        window: &mut Window,
 3090        cx: &mut Context<Self>,
 3091    ) {
 3092        self.show_edit_predictions_override = show_edit_predictions;
 3093        self.update_edit_prediction_settings(cx);
 3094
 3095        if let Some(false) = show_edit_predictions {
 3096            self.discard_edit_prediction(false, cx);
 3097        } else {
 3098            self.refresh_edit_prediction(false, true, window, cx);
 3099        }
 3100    }
 3101
 3102    fn edit_predictions_disabled_in_scope(
 3103        &self,
 3104        buffer: &Entity<Buffer>,
 3105        buffer_position: language::Anchor,
 3106        cx: &App,
 3107    ) -> bool {
 3108        let snapshot = buffer.read(cx).snapshot();
 3109        let settings = snapshot.settings_at(buffer_position, cx);
 3110
 3111        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 3112            return false;
 3113        };
 3114
 3115        scope.override_name().is_some_and(|scope_name| {
 3116            settings
 3117                .edit_predictions_disabled_in
 3118                .iter()
 3119                .any(|s| s == scope_name)
 3120        })
 3121    }
 3122
 3123    pub fn set_use_modal_editing(&mut self, to: bool) {
 3124        self.use_modal_editing = to;
 3125    }
 3126
 3127    pub fn use_modal_editing(&self) -> bool {
 3128        self.use_modal_editing
 3129    }
 3130
 3131    fn selections_did_change(
 3132        &mut self,
 3133        local: bool,
 3134        old_cursor_position: &Anchor,
 3135        effects: SelectionEffects,
 3136        window: &mut Window,
 3137        cx: &mut Context<Self>,
 3138    ) {
 3139        window.invalidate_character_coordinates();
 3140
 3141        // Copy selections to primary selection buffer
 3142        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 3143        if local {
 3144            let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
 3145            let buffer_handle = self.buffer.read(cx).read(cx);
 3146
 3147            let mut text = String::new();
 3148            for (index, selection) in selections.iter().enumerate() {
 3149                let text_for_selection = buffer_handle
 3150                    .text_for_range(selection.start..selection.end)
 3151                    .collect::<String>();
 3152
 3153                text.push_str(&text_for_selection);
 3154                if index != selections.len() - 1 {
 3155                    text.push('\n');
 3156                }
 3157            }
 3158
 3159            if !text.is_empty() {
 3160                cx.write_to_primary(ClipboardItem::new_string(text));
 3161            }
 3162        }
 3163
 3164        let selection_anchors = self.selections.disjoint_anchors_arc();
 3165
 3166        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 3167            self.buffer.update(cx, |buffer, cx| {
 3168                buffer.set_active_selections(
 3169                    &selection_anchors,
 3170                    self.selections.line_mode(),
 3171                    self.cursor_shape,
 3172                    cx,
 3173                )
 3174            });
 3175        }
 3176        let display_map = self
 3177            .display_map
 3178            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3179        let buffer = display_map.buffer_snapshot();
 3180        if self.selections.count() == 1 {
 3181            self.add_selections_state = None;
 3182        }
 3183        self.select_next_state = None;
 3184        self.select_prev_state = None;
 3185        self.select_syntax_node_history.try_clear();
 3186        self.invalidate_autoclose_regions(&selection_anchors, buffer);
 3187        self.snippet_stack.invalidate(&selection_anchors, buffer);
 3188        self.take_rename(false, window, cx);
 3189
 3190        let newest_selection = self.selections.newest_anchor();
 3191        let new_cursor_position = newest_selection.head();
 3192        let selection_start = newest_selection.start;
 3193
 3194        if effects.nav_history.is_none() || effects.nav_history == Some(true) {
 3195            self.push_to_nav_history(
 3196                *old_cursor_position,
 3197                Some(new_cursor_position.to_point(buffer)),
 3198                false,
 3199                effects.nav_history == Some(true),
 3200                cx,
 3201            );
 3202        }
 3203
 3204        if local {
 3205            if let Some(buffer_id) = new_cursor_position.buffer_id {
 3206                self.register_buffer(buffer_id, cx);
 3207            }
 3208
 3209            let mut context_menu = self.context_menu.borrow_mut();
 3210            let completion_menu = match context_menu.as_ref() {
 3211                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 3212                Some(CodeContextMenu::CodeActions(_)) => {
 3213                    *context_menu = None;
 3214                    None
 3215                }
 3216                None => None,
 3217            };
 3218            let completion_position = completion_menu.map(|menu| menu.initial_position);
 3219            drop(context_menu);
 3220
 3221            if effects.completions
 3222                && let Some(completion_position) = completion_position
 3223            {
 3224                let start_offset = selection_start.to_offset(buffer);
 3225                let position_matches = start_offset == completion_position.to_offset(buffer);
 3226                let continue_showing = if position_matches {
 3227                    if self.snippet_stack.is_empty() {
 3228                        buffer.char_kind_before(start_offset, Some(CharScopeContext::Completion))
 3229                            == Some(CharKind::Word)
 3230                    } else {
 3231                        // Snippet choices can be shown even when the cursor is in whitespace.
 3232                        // Dismissing the menu with actions like backspace is handled by
 3233                        // invalidation regions.
 3234                        true
 3235                    }
 3236                } else {
 3237                    false
 3238                };
 3239
 3240                if continue_showing {
 3241                    self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 3242                } else {
 3243                    self.hide_context_menu(window, cx);
 3244                }
 3245            }
 3246
 3247            hide_hover(self, cx);
 3248
 3249            if old_cursor_position.to_display_point(&display_map).row()
 3250                != new_cursor_position.to_display_point(&display_map).row()
 3251            {
 3252                self.available_code_actions.take();
 3253            }
 3254            self.refresh_code_actions(window, cx);
 3255            self.refresh_document_highlights(cx);
 3256            refresh_linked_ranges(self, window, cx);
 3257
 3258            self.refresh_selected_text_highlights(false, window, cx);
 3259            self.refresh_matching_bracket_highlights(window, cx);
 3260            self.update_visible_edit_prediction(window, cx);
 3261            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 3262            self.inline_blame_popover.take();
 3263            if self.git_blame_inline_enabled {
 3264                self.start_inline_blame_timer(window, cx);
 3265            }
 3266        }
 3267
 3268        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 3269        cx.emit(EditorEvent::SelectionsChanged { local });
 3270
 3271        let selections = &self.selections.disjoint_anchors_arc();
 3272        if selections.len() == 1 {
 3273            cx.emit(SearchEvent::ActiveMatchChanged)
 3274        }
 3275        if local && let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 3276            let inmemory_selections = selections
 3277                .iter()
 3278                .map(|s| {
 3279                    text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 3280                        ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 3281                })
 3282                .collect();
 3283            self.update_restoration_data(cx, |data| {
 3284                data.selections = inmemory_selections;
 3285            });
 3286
 3287            if WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
 3288                && let Some(workspace_id) = self.workspace_serialization_id(cx)
 3289            {
 3290                let snapshot = self.buffer().read(cx).snapshot(cx);
 3291                let selections = selections.clone();
 3292                let background_executor = cx.background_executor().clone();
 3293                let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3294                self.serialize_selections = cx.background_spawn(async move {
 3295                    background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3296                    let db_selections = selections
 3297                        .iter()
 3298                        .map(|selection| {
 3299                            (
 3300                                selection.start.to_offset(&snapshot),
 3301                                selection.end.to_offset(&snapshot),
 3302                            )
 3303                        })
 3304                        .collect();
 3305
 3306                    DB.save_editor_selections(editor_id, workspace_id, db_selections)
 3307                        .await
 3308                        .with_context(|| {
 3309                            format!(
 3310                                "persisting editor selections for editor {editor_id}, \
 3311                                workspace {workspace_id:?}"
 3312                            )
 3313                        })
 3314                        .log_err();
 3315                });
 3316            }
 3317        }
 3318
 3319        cx.notify();
 3320    }
 3321
 3322    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 3323        use text::ToOffset as _;
 3324        use text::ToPoint as _;
 3325
 3326        if self.mode.is_minimap()
 3327            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 3328        {
 3329            return;
 3330        }
 3331
 3332        if !self.buffer().read(cx).is_singleton() {
 3333            return;
 3334        }
 3335
 3336        let display_snapshot = self
 3337            .display_map
 3338            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3339        let Some((.., snapshot)) = display_snapshot.buffer_snapshot().as_singleton() else {
 3340            return;
 3341        };
 3342        let inmemory_folds = display_snapshot
 3343            .folds_in_range(0..display_snapshot.buffer_snapshot().len())
 3344            .map(|fold| {
 3345                fold.range.start.text_anchor.to_point(&snapshot)
 3346                    ..fold.range.end.text_anchor.to_point(&snapshot)
 3347            })
 3348            .collect();
 3349        self.update_restoration_data(cx, |data| {
 3350            data.folds = inmemory_folds;
 3351        });
 3352
 3353        let Some(workspace_id) = self.workspace_serialization_id(cx) else {
 3354            return;
 3355        };
 3356        let background_executor = cx.background_executor().clone();
 3357        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3358        let db_folds = display_snapshot
 3359            .folds_in_range(0..display_snapshot.buffer_snapshot().len())
 3360            .map(|fold| {
 3361                (
 3362                    fold.range.start.text_anchor.to_offset(&snapshot),
 3363                    fold.range.end.text_anchor.to_offset(&snapshot),
 3364                )
 3365            })
 3366            .collect();
 3367        self.serialize_folds = cx.background_spawn(async move {
 3368            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3369            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 3370                .await
 3371                .with_context(|| {
 3372                    format!(
 3373                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 3374                    )
 3375                })
 3376                .log_err();
 3377        });
 3378    }
 3379
 3380    pub fn sync_selections(
 3381        &mut self,
 3382        other: Entity<Editor>,
 3383        cx: &mut Context<Self>,
 3384    ) -> gpui::Subscription {
 3385        let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3386        if !other_selections.is_empty() {
 3387            self.selections
 3388                .change_with(&self.display_snapshot(cx), |selections| {
 3389                    selections.select_anchors(other_selections);
 3390                });
 3391        }
 3392
 3393        let other_subscription = cx.subscribe(&other, |this, other, other_evt, cx| {
 3394            if let EditorEvent::SelectionsChanged { local: true } = other_evt {
 3395                let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3396                if other_selections.is_empty() {
 3397                    return;
 3398                }
 3399                let snapshot = this.display_snapshot(cx);
 3400                this.selections.change_with(&snapshot, |selections| {
 3401                    selections.select_anchors(other_selections);
 3402                });
 3403            }
 3404        });
 3405
 3406        let this_subscription = cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| {
 3407            if let EditorEvent::SelectionsChanged { local: true } = this_evt {
 3408                let these_selections = this.selections.disjoint_anchors().to_vec();
 3409                if these_selections.is_empty() {
 3410                    return;
 3411                }
 3412                other.update(cx, |other_editor, cx| {
 3413                    let snapshot = other_editor.display_snapshot(cx);
 3414                    other_editor
 3415                        .selections
 3416                        .change_with(&snapshot, |selections| {
 3417                            selections.select_anchors(these_selections);
 3418                        })
 3419                });
 3420            }
 3421        });
 3422
 3423        Subscription::join(other_subscription, this_subscription)
 3424    }
 3425
 3426    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 3427    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 3428    /// effects of selection change occur at the end of the transaction.
 3429    pub fn change_selections<R>(
 3430        &mut self,
 3431        effects: SelectionEffects,
 3432        window: &mut Window,
 3433        cx: &mut Context<Self>,
 3434        change: impl FnOnce(&mut MutableSelectionsCollection<'_, '_>) -> R,
 3435    ) -> R {
 3436        let snapshot = self.display_snapshot(cx);
 3437        if let Some(state) = &mut self.deferred_selection_effects_state {
 3438            state.effects.scroll = effects.scroll.or(state.effects.scroll);
 3439            state.effects.completions = effects.completions;
 3440            state.effects.nav_history = effects.nav_history.or(state.effects.nav_history);
 3441            let (changed, result) = self.selections.change_with(&snapshot, change);
 3442            state.changed |= changed;
 3443            return result;
 3444        }
 3445        let mut state = DeferredSelectionEffectsState {
 3446            changed: false,
 3447            effects,
 3448            old_cursor_position: self.selections.newest_anchor().head(),
 3449            history_entry: SelectionHistoryEntry {
 3450                selections: self.selections.disjoint_anchors_arc(),
 3451                select_next_state: self.select_next_state.clone(),
 3452                select_prev_state: self.select_prev_state.clone(),
 3453                add_selections_state: self.add_selections_state.clone(),
 3454            },
 3455        };
 3456        let (changed, result) = self.selections.change_with(&snapshot, change);
 3457        state.changed = state.changed || changed;
 3458        if self.defer_selection_effects {
 3459            self.deferred_selection_effects_state = Some(state);
 3460        } else {
 3461            self.apply_selection_effects(state, window, cx);
 3462        }
 3463        result
 3464    }
 3465
 3466    /// Defers the effects of selection change, so that the effects of multiple calls to
 3467    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3468    /// to selection history and the state of popovers based on selection position aren't
 3469    /// erroneously updated.
 3470    pub fn with_selection_effects_deferred<R>(
 3471        &mut self,
 3472        window: &mut Window,
 3473        cx: &mut Context<Self>,
 3474        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3475    ) -> R {
 3476        let already_deferred = self.defer_selection_effects;
 3477        self.defer_selection_effects = true;
 3478        let result = update(self, window, cx);
 3479        if !already_deferred {
 3480            self.defer_selection_effects = false;
 3481            if let Some(state) = self.deferred_selection_effects_state.take() {
 3482                self.apply_selection_effects(state, window, cx);
 3483            }
 3484        }
 3485        result
 3486    }
 3487
 3488    fn apply_selection_effects(
 3489        &mut self,
 3490        state: DeferredSelectionEffectsState,
 3491        window: &mut Window,
 3492        cx: &mut Context<Self>,
 3493    ) {
 3494        if state.changed {
 3495            self.selection_history.push(state.history_entry);
 3496
 3497            if let Some(autoscroll) = state.effects.scroll {
 3498                self.request_autoscroll(autoscroll, cx);
 3499            }
 3500
 3501            let old_cursor_position = &state.old_cursor_position;
 3502
 3503            self.selections_did_change(true, old_cursor_position, state.effects, window, cx);
 3504
 3505            if self.should_open_signature_help_automatically(old_cursor_position, cx) {
 3506                self.show_signature_help(&ShowSignatureHelp, window, cx);
 3507            }
 3508        }
 3509    }
 3510
 3511    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3512    where
 3513        I: IntoIterator<Item = (Range<S>, T)>,
 3514        S: ToOffset,
 3515        T: Into<Arc<str>>,
 3516    {
 3517        if self.read_only(cx) {
 3518            return;
 3519        }
 3520
 3521        self.buffer
 3522            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3523    }
 3524
 3525    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3526    where
 3527        I: IntoIterator<Item = (Range<S>, T)>,
 3528        S: ToOffset,
 3529        T: Into<Arc<str>>,
 3530    {
 3531        if self.read_only(cx) {
 3532            return;
 3533        }
 3534
 3535        self.buffer.update(cx, |buffer, cx| {
 3536            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3537        });
 3538    }
 3539
 3540    pub fn edit_with_block_indent<I, S, T>(
 3541        &mut self,
 3542        edits: I,
 3543        original_indent_columns: Vec<Option<u32>>,
 3544        cx: &mut Context<Self>,
 3545    ) where
 3546        I: IntoIterator<Item = (Range<S>, T)>,
 3547        S: ToOffset,
 3548        T: Into<Arc<str>>,
 3549    {
 3550        if self.read_only(cx) {
 3551            return;
 3552        }
 3553
 3554        self.buffer.update(cx, |buffer, cx| {
 3555            buffer.edit(
 3556                edits,
 3557                Some(AutoindentMode::Block {
 3558                    original_indent_columns,
 3559                }),
 3560                cx,
 3561            )
 3562        });
 3563    }
 3564
 3565    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3566        self.hide_context_menu(window, cx);
 3567
 3568        match phase {
 3569            SelectPhase::Begin {
 3570                position,
 3571                add,
 3572                click_count,
 3573            } => self.begin_selection(position, add, click_count, window, cx),
 3574            SelectPhase::BeginColumnar {
 3575                position,
 3576                goal_column,
 3577                reset,
 3578                mode,
 3579            } => self.begin_columnar_selection(position, goal_column, reset, mode, window, cx),
 3580            SelectPhase::Extend {
 3581                position,
 3582                click_count,
 3583            } => self.extend_selection(position, click_count, window, cx),
 3584            SelectPhase::Update {
 3585                position,
 3586                goal_column,
 3587                scroll_delta,
 3588            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3589            SelectPhase::End => self.end_selection(window, cx),
 3590        }
 3591    }
 3592
 3593    fn extend_selection(
 3594        &mut self,
 3595        position: DisplayPoint,
 3596        click_count: usize,
 3597        window: &mut Window,
 3598        cx: &mut Context<Self>,
 3599    ) {
 3600        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3601        let tail = self.selections.newest::<usize>(&display_map).tail();
 3602        let click_count = click_count.max(match self.selections.select_mode() {
 3603            SelectMode::Character => 1,
 3604            SelectMode::Word(_) => 2,
 3605            SelectMode::Line(_) => 3,
 3606            SelectMode::All => 4,
 3607        });
 3608        self.begin_selection(position, false, click_count, window, cx);
 3609
 3610        let tail_anchor = display_map.buffer_snapshot().anchor_before(tail);
 3611
 3612        let current_selection = match self.selections.select_mode() {
 3613            SelectMode::Character | SelectMode::All => tail_anchor..tail_anchor,
 3614            SelectMode::Word(range) | SelectMode::Line(range) => range.clone(),
 3615        };
 3616
 3617        let mut pending_selection = self
 3618            .selections
 3619            .pending_anchor()
 3620            .cloned()
 3621            .expect("extend_selection not called with pending selection");
 3622
 3623        if pending_selection
 3624            .start
 3625            .cmp(&current_selection.start, display_map.buffer_snapshot())
 3626            == Ordering::Greater
 3627        {
 3628            pending_selection.start = current_selection.start;
 3629        }
 3630        if pending_selection
 3631            .end
 3632            .cmp(&current_selection.end, display_map.buffer_snapshot())
 3633            == Ordering::Less
 3634        {
 3635            pending_selection.end = current_selection.end;
 3636            pending_selection.reversed = true;
 3637        }
 3638
 3639        let mut pending_mode = self.selections.pending_mode().unwrap();
 3640        match &mut pending_mode {
 3641            SelectMode::Word(range) | SelectMode::Line(range) => *range = current_selection,
 3642            _ => {}
 3643        }
 3644
 3645        let effects = if EditorSettings::get_global(cx).autoscroll_on_clicks {
 3646            SelectionEffects::scroll(Autoscroll::fit())
 3647        } else {
 3648            SelectionEffects::no_scroll()
 3649        };
 3650
 3651        self.change_selections(effects, window, cx, |s| {
 3652            s.set_pending(pending_selection.clone(), pending_mode);
 3653            s.set_is_extending(true);
 3654        });
 3655    }
 3656
 3657    fn begin_selection(
 3658        &mut self,
 3659        position: DisplayPoint,
 3660        add: bool,
 3661        click_count: usize,
 3662        window: &mut Window,
 3663        cx: &mut Context<Self>,
 3664    ) {
 3665        if !self.focus_handle.is_focused(window) {
 3666            self.last_focused_descendant = None;
 3667            window.focus(&self.focus_handle);
 3668        }
 3669
 3670        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3671        let buffer = display_map.buffer_snapshot();
 3672        let position = display_map.clip_point(position, Bias::Left);
 3673
 3674        let start;
 3675        let end;
 3676        let mode;
 3677        let mut auto_scroll;
 3678        match click_count {
 3679            1 => {
 3680                start = buffer.anchor_before(position.to_point(&display_map));
 3681                end = start;
 3682                mode = SelectMode::Character;
 3683                auto_scroll = true;
 3684            }
 3685            2 => {
 3686                let position = display_map
 3687                    .clip_point(position, Bias::Left)
 3688                    .to_offset(&display_map, Bias::Left);
 3689                let (range, _) = buffer.surrounding_word(position, None);
 3690                start = buffer.anchor_before(range.start);
 3691                end = buffer.anchor_before(range.end);
 3692                mode = SelectMode::Word(start..end);
 3693                auto_scroll = true;
 3694            }
 3695            3 => {
 3696                let position = display_map
 3697                    .clip_point(position, Bias::Left)
 3698                    .to_point(&display_map);
 3699                let line_start = display_map.prev_line_boundary(position).0;
 3700                let next_line_start = buffer.clip_point(
 3701                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3702                    Bias::Left,
 3703                );
 3704                start = buffer.anchor_before(line_start);
 3705                end = buffer.anchor_before(next_line_start);
 3706                mode = SelectMode::Line(start..end);
 3707                auto_scroll = true;
 3708            }
 3709            _ => {
 3710                start = buffer.anchor_before(0);
 3711                end = buffer.anchor_before(buffer.len());
 3712                mode = SelectMode::All;
 3713                auto_scroll = false;
 3714            }
 3715        }
 3716        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3717
 3718        let point_to_delete: Option<usize> = {
 3719            let selected_points: Vec<Selection<Point>> =
 3720                self.selections.disjoint_in_range(start..end, &display_map);
 3721
 3722            if !add || click_count > 1 {
 3723                None
 3724            } else if !selected_points.is_empty() {
 3725                Some(selected_points[0].id)
 3726            } else {
 3727                let clicked_point_already_selected =
 3728                    self.selections.disjoint_anchors().iter().find(|selection| {
 3729                        selection.start.to_point(buffer) == start.to_point(buffer)
 3730                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3731                    });
 3732
 3733                clicked_point_already_selected.map(|selection| selection.id)
 3734            }
 3735        };
 3736
 3737        let selections_count = self.selections.count();
 3738        let effects = if auto_scroll {
 3739            SelectionEffects::default()
 3740        } else {
 3741            SelectionEffects::no_scroll()
 3742        };
 3743
 3744        self.change_selections(effects, window, cx, |s| {
 3745            if let Some(point_to_delete) = point_to_delete {
 3746                s.delete(point_to_delete);
 3747
 3748                if selections_count == 1 {
 3749                    s.set_pending_anchor_range(start..end, mode);
 3750                }
 3751            } else {
 3752                if !add {
 3753                    s.clear_disjoint();
 3754                }
 3755
 3756                s.set_pending_anchor_range(start..end, mode);
 3757            }
 3758        });
 3759    }
 3760
 3761    fn begin_columnar_selection(
 3762        &mut self,
 3763        position: DisplayPoint,
 3764        goal_column: u32,
 3765        reset: bool,
 3766        mode: ColumnarMode,
 3767        window: &mut Window,
 3768        cx: &mut Context<Self>,
 3769    ) {
 3770        if !self.focus_handle.is_focused(window) {
 3771            self.last_focused_descendant = None;
 3772            window.focus(&self.focus_handle);
 3773        }
 3774
 3775        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3776
 3777        if reset {
 3778            let pointer_position = display_map
 3779                .buffer_snapshot()
 3780                .anchor_before(position.to_point(&display_map));
 3781
 3782            self.change_selections(
 3783                SelectionEffects::scroll(Autoscroll::newest()),
 3784                window,
 3785                cx,
 3786                |s| {
 3787                    s.clear_disjoint();
 3788                    s.set_pending_anchor_range(
 3789                        pointer_position..pointer_position,
 3790                        SelectMode::Character,
 3791                    );
 3792                },
 3793            );
 3794        };
 3795
 3796        let tail = self.selections.newest::<Point>(&display_map).tail();
 3797        let selection_anchor = display_map.buffer_snapshot().anchor_before(tail);
 3798        self.columnar_selection_state = match mode {
 3799            ColumnarMode::FromMouse => Some(ColumnarSelectionState::FromMouse {
 3800                selection_tail: selection_anchor,
 3801                display_point: if reset {
 3802                    if position.column() != goal_column {
 3803                        Some(DisplayPoint::new(position.row(), goal_column))
 3804                    } else {
 3805                        None
 3806                    }
 3807                } else {
 3808                    None
 3809                },
 3810            }),
 3811            ColumnarMode::FromSelection => Some(ColumnarSelectionState::FromSelection {
 3812                selection_tail: selection_anchor,
 3813            }),
 3814        };
 3815
 3816        if !reset {
 3817            self.select_columns(position, goal_column, &display_map, window, cx);
 3818        }
 3819    }
 3820
 3821    fn update_selection(
 3822        &mut self,
 3823        position: DisplayPoint,
 3824        goal_column: u32,
 3825        scroll_delta: gpui::Point<f32>,
 3826        window: &mut Window,
 3827        cx: &mut Context<Self>,
 3828    ) {
 3829        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3830
 3831        if self.columnar_selection_state.is_some() {
 3832            self.select_columns(position, goal_column, &display_map, window, cx);
 3833        } else if let Some(mut pending) = self.selections.pending_anchor().cloned() {
 3834            let buffer = display_map.buffer_snapshot();
 3835            let head;
 3836            let tail;
 3837            let mode = self.selections.pending_mode().unwrap();
 3838            match &mode {
 3839                SelectMode::Character => {
 3840                    head = position.to_point(&display_map);
 3841                    tail = pending.tail().to_point(buffer);
 3842                }
 3843                SelectMode::Word(original_range) => {
 3844                    let offset = display_map
 3845                        .clip_point(position, Bias::Left)
 3846                        .to_offset(&display_map, Bias::Left);
 3847                    let original_range = original_range.to_offset(buffer);
 3848
 3849                    let head_offset = if buffer.is_inside_word(offset, None)
 3850                        || original_range.contains(&offset)
 3851                    {
 3852                        let (word_range, _) = buffer.surrounding_word(offset, None);
 3853                        if word_range.start < original_range.start {
 3854                            word_range.start
 3855                        } else {
 3856                            word_range.end
 3857                        }
 3858                    } else {
 3859                        offset
 3860                    };
 3861
 3862                    head = head_offset.to_point(buffer);
 3863                    if head_offset <= original_range.start {
 3864                        tail = original_range.end.to_point(buffer);
 3865                    } else {
 3866                        tail = original_range.start.to_point(buffer);
 3867                    }
 3868                }
 3869                SelectMode::Line(original_range) => {
 3870                    let original_range = original_range.to_point(display_map.buffer_snapshot());
 3871
 3872                    let position = display_map
 3873                        .clip_point(position, Bias::Left)
 3874                        .to_point(&display_map);
 3875                    let line_start = display_map.prev_line_boundary(position).0;
 3876                    let next_line_start = buffer.clip_point(
 3877                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3878                        Bias::Left,
 3879                    );
 3880
 3881                    if line_start < original_range.start {
 3882                        head = line_start
 3883                    } else {
 3884                        head = next_line_start
 3885                    }
 3886
 3887                    if head <= original_range.start {
 3888                        tail = original_range.end;
 3889                    } else {
 3890                        tail = original_range.start;
 3891                    }
 3892                }
 3893                SelectMode::All => {
 3894                    return;
 3895                }
 3896            };
 3897
 3898            if head < tail {
 3899                pending.start = buffer.anchor_before(head);
 3900                pending.end = buffer.anchor_before(tail);
 3901                pending.reversed = true;
 3902            } else {
 3903                pending.start = buffer.anchor_before(tail);
 3904                pending.end = buffer.anchor_before(head);
 3905                pending.reversed = false;
 3906            }
 3907
 3908            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3909                s.set_pending(pending.clone(), mode);
 3910            });
 3911        } else {
 3912            log::error!("update_selection dispatched with no pending selection");
 3913            return;
 3914        }
 3915
 3916        self.apply_scroll_delta(scroll_delta, window, cx);
 3917        cx.notify();
 3918    }
 3919
 3920    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3921        self.columnar_selection_state.take();
 3922        if let Some(pending_mode) = self.selections.pending_mode() {
 3923            let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
 3924            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3925                s.select(selections);
 3926                s.clear_pending();
 3927                if s.is_extending() {
 3928                    s.set_is_extending(false);
 3929                } else {
 3930                    s.set_select_mode(pending_mode);
 3931                }
 3932            });
 3933        }
 3934    }
 3935
 3936    fn select_columns(
 3937        &mut self,
 3938        head: DisplayPoint,
 3939        goal_column: u32,
 3940        display_map: &DisplaySnapshot,
 3941        window: &mut Window,
 3942        cx: &mut Context<Self>,
 3943    ) {
 3944        let Some(columnar_state) = self.columnar_selection_state.as_ref() else {
 3945            return;
 3946        };
 3947
 3948        let tail = match columnar_state {
 3949            ColumnarSelectionState::FromMouse {
 3950                selection_tail,
 3951                display_point,
 3952            } => display_point.unwrap_or_else(|| selection_tail.to_display_point(display_map)),
 3953            ColumnarSelectionState::FromSelection { selection_tail } => {
 3954                selection_tail.to_display_point(display_map)
 3955            }
 3956        };
 3957
 3958        let start_row = cmp::min(tail.row(), head.row());
 3959        let end_row = cmp::max(tail.row(), head.row());
 3960        let start_column = cmp::min(tail.column(), goal_column);
 3961        let end_column = cmp::max(tail.column(), goal_column);
 3962        let reversed = start_column < tail.column();
 3963
 3964        let selection_ranges = (start_row.0..=end_row.0)
 3965            .map(DisplayRow)
 3966            .filter_map(|row| {
 3967                if (matches!(columnar_state, ColumnarSelectionState::FromMouse { .. })
 3968                    || start_column <= display_map.line_len(row))
 3969                    && !display_map.is_block_line(row)
 3970                {
 3971                    let start = display_map
 3972                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 3973                        .to_point(display_map);
 3974                    let end = display_map
 3975                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 3976                        .to_point(display_map);
 3977                    if reversed {
 3978                        Some(end..start)
 3979                    } else {
 3980                        Some(start..end)
 3981                    }
 3982                } else {
 3983                    None
 3984                }
 3985            })
 3986            .collect::<Vec<_>>();
 3987        if selection_ranges.is_empty() {
 3988            return;
 3989        }
 3990
 3991        let ranges = match columnar_state {
 3992            ColumnarSelectionState::FromMouse { .. } => {
 3993                let mut non_empty_ranges = selection_ranges
 3994                    .iter()
 3995                    .filter(|selection_range| selection_range.start != selection_range.end)
 3996                    .peekable();
 3997                if non_empty_ranges.peek().is_some() {
 3998                    non_empty_ranges.cloned().collect()
 3999                } else {
 4000                    selection_ranges
 4001                }
 4002            }
 4003            _ => selection_ranges,
 4004        };
 4005
 4006        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 4007            s.select_ranges(ranges);
 4008        });
 4009        cx.notify();
 4010    }
 4011
 4012    pub fn has_non_empty_selection(&self, snapshot: &DisplaySnapshot) -> bool {
 4013        self.selections
 4014            .all_adjusted(snapshot)
 4015            .iter()
 4016            .any(|selection| !selection.is_empty())
 4017    }
 4018
 4019    pub fn has_pending_nonempty_selection(&self) -> bool {
 4020        let pending_nonempty_selection = match self.selections.pending_anchor() {
 4021            Some(Selection { start, end, .. }) => start != end,
 4022            None => false,
 4023        };
 4024
 4025        pending_nonempty_selection
 4026            || (self.columnar_selection_state.is_some()
 4027                && self.selections.disjoint_anchors().len() > 1)
 4028    }
 4029
 4030    pub fn has_pending_selection(&self) -> bool {
 4031        self.selections.pending_anchor().is_some() || self.columnar_selection_state.is_some()
 4032    }
 4033
 4034    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 4035        self.selection_mark_mode = false;
 4036        self.selection_drag_state = SelectionDragState::None;
 4037
 4038        if self.clear_expanded_diff_hunks(cx) {
 4039            cx.notify();
 4040            return;
 4041        }
 4042        if self.dismiss_menus_and_popups(true, window, cx) {
 4043            return;
 4044        }
 4045
 4046        if self.mode.is_full()
 4047            && self.change_selections(Default::default(), window, cx, |s| s.try_cancel())
 4048        {
 4049            return;
 4050        }
 4051
 4052        cx.propagate();
 4053    }
 4054
 4055    pub fn dismiss_menus_and_popups(
 4056        &mut self,
 4057        is_user_requested: bool,
 4058        window: &mut Window,
 4059        cx: &mut Context<Self>,
 4060    ) -> bool {
 4061        if self.take_rename(false, window, cx).is_some() {
 4062            return true;
 4063        }
 4064
 4065        if self.hide_blame_popover(true, cx) {
 4066            return true;
 4067        }
 4068
 4069        if hide_hover(self, cx) {
 4070            return true;
 4071        }
 4072
 4073        if self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape) {
 4074            return true;
 4075        }
 4076
 4077        if self.hide_context_menu(window, cx).is_some() {
 4078            return true;
 4079        }
 4080
 4081        if self.mouse_context_menu.take().is_some() {
 4082            return true;
 4083        }
 4084
 4085        if is_user_requested && self.discard_edit_prediction(true, cx) {
 4086            return true;
 4087        }
 4088
 4089        if self.snippet_stack.pop().is_some() {
 4090            return true;
 4091        }
 4092
 4093        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 4094            self.dismiss_diagnostics(cx);
 4095            return true;
 4096        }
 4097
 4098        false
 4099    }
 4100
 4101    fn linked_editing_ranges_for(
 4102        &self,
 4103        selection: Range<text::Anchor>,
 4104        cx: &App,
 4105    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 4106        if self.linked_edit_ranges.is_empty() {
 4107            return None;
 4108        }
 4109        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 4110            selection.end.buffer_id.and_then(|end_buffer_id| {
 4111                if selection.start.buffer_id != Some(end_buffer_id) {
 4112                    return None;
 4113                }
 4114                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 4115                let snapshot = buffer.read(cx).snapshot();
 4116                self.linked_edit_ranges
 4117                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 4118                    .map(|ranges| (ranges, snapshot, buffer))
 4119            })?;
 4120        use text::ToOffset as TO;
 4121        // find offset from the start of current range to current cursor position
 4122        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 4123
 4124        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 4125        let start_difference = start_offset - start_byte_offset;
 4126        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 4127        let end_difference = end_offset - start_byte_offset;
 4128        // Current range has associated linked ranges.
 4129        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4130        for range in linked_ranges.iter() {
 4131            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 4132            let end_offset = start_offset + end_difference;
 4133            let start_offset = start_offset + start_difference;
 4134            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 4135                continue;
 4136            }
 4137            if self.selections.disjoint_anchor_ranges().any(|s| {
 4138                if s.start.buffer_id != selection.start.buffer_id
 4139                    || s.end.buffer_id != selection.end.buffer_id
 4140                {
 4141                    return false;
 4142                }
 4143                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 4144                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 4145            }) {
 4146                continue;
 4147            }
 4148            let start = buffer_snapshot.anchor_after(start_offset);
 4149            let end = buffer_snapshot.anchor_after(end_offset);
 4150            linked_edits
 4151                .entry(buffer.clone())
 4152                .or_default()
 4153                .push(start..end);
 4154        }
 4155        Some(linked_edits)
 4156    }
 4157
 4158    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4159        let text: Arc<str> = text.into();
 4160
 4161        if self.read_only(cx) {
 4162            return;
 4163        }
 4164
 4165        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4166
 4167        let selections = self.selections.all_adjusted(&self.display_snapshot(cx));
 4168        let mut bracket_inserted = false;
 4169        let mut edits = Vec::new();
 4170        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4171        let mut new_selections = Vec::with_capacity(selections.len());
 4172        let mut new_autoclose_regions = Vec::new();
 4173        let snapshot = self.buffer.read(cx).read(cx);
 4174        let mut clear_linked_edit_ranges = false;
 4175
 4176        for (selection, autoclose_region) in
 4177            self.selections_with_autoclose_regions(selections, &snapshot)
 4178        {
 4179            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 4180                // Determine if the inserted text matches the opening or closing
 4181                // bracket of any of this language's bracket pairs.
 4182                let mut bracket_pair = None;
 4183                let mut is_bracket_pair_start = false;
 4184                let mut is_bracket_pair_end = false;
 4185                if !text.is_empty() {
 4186                    let mut bracket_pair_matching_end = None;
 4187                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 4188                    //  and they are removing the character that triggered IME popup.
 4189                    for (pair, enabled) in scope.brackets() {
 4190                        if !pair.close && !pair.surround {
 4191                            continue;
 4192                        }
 4193
 4194                        if enabled && pair.start.ends_with(text.as_ref()) {
 4195                            let prefix_len = pair.start.len() - text.len();
 4196                            let preceding_text_matches_prefix = prefix_len == 0
 4197                                || (selection.start.column >= (prefix_len as u32)
 4198                                    && snapshot.contains_str_at(
 4199                                        Point::new(
 4200                                            selection.start.row,
 4201                                            selection.start.column - (prefix_len as u32),
 4202                                        ),
 4203                                        &pair.start[..prefix_len],
 4204                                    ));
 4205                            if preceding_text_matches_prefix {
 4206                                bracket_pair = Some(pair.clone());
 4207                                is_bracket_pair_start = true;
 4208                                break;
 4209                            }
 4210                        }
 4211                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 4212                        {
 4213                            // take first bracket pair matching end, but don't break in case a later bracket
 4214                            // pair matches start
 4215                            bracket_pair_matching_end = Some(pair.clone());
 4216                        }
 4217                    }
 4218                    if let Some(end) = bracket_pair_matching_end
 4219                        && bracket_pair.is_none()
 4220                    {
 4221                        bracket_pair = Some(end);
 4222                        is_bracket_pair_end = true;
 4223                    }
 4224                }
 4225
 4226                if let Some(bracket_pair) = bracket_pair {
 4227                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 4228                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 4229                    let auto_surround =
 4230                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 4231                    if selection.is_empty() {
 4232                        if is_bracket_pair_start {
 4233                            // If the inserted text is a suffix of an opening bracket and the
 4234                            // selection is preceded by the rest of the opening bracket, then
 4235                            // insert the closing bracket.
 4236                            let following_text_allows_autoclose = snapshot
 4237                                .chars_at(selection.start)
 4238                                .next()
 4239                                .is_none_or(|c| scope.should_autoclose_before(c));
 4240
 4241                            let preceding_text_allows_autoclose = selection.start.column == 0
 4242                                || snapshot
 4243                                    .reversed_chars_at(selection.start)
 4244                                    .next()
 4245                                    .is_none_or(|c| {
 4246                                        bracket_pair.start != bracket_pair.end
 4247                                            || !snapshot
 4248                                                .char_classifier_at(selection.start)
 4249                                                .is_word(c)
 4250                                    });
 4251
 4252                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 4253                                && bracket_pair.start.len() == 1
 4254                            {
 4255                                let target = bracket_pair.start.chars().next().unwrap();
 4256                                let current_line_count = snapshot
 4257                                    .reversed_chars_at(selection.start)
 4258                                    .take_while(|&c| c != '\n')
 4259                                    .filter(|&c| c == target)
 4260                                    .count();
 4261                                current_line_count % 2 == 1
 4262                            } else {
 4263                                false
 4264                            };
 4265
 4266                            if autoclose
 4267                                && bracket_pair.close
 4268                                && following_text_allows_autoclose
 4269                                && preceding_text_allows_autoclose
 4270                                && !is_closing_quote
 4271                            {
 4272                                let anchor = snapshot.anchor_before(selection.end);
 4273                                new_selections.push((selection.map(|_| anchor), text.len()));
 4274                                new_autoclose_regions.push((
 4275                                    anchor,
 4276                                    text.len(),
 4277                                    selection.id,
 4278                                    bracket_pair.clone(),
 4279                                ));
 4280                                edits.push((
 4281                                    selection.range(),
 4282                                    format!("{}{}", text, bracket_pair.end).into(),
 4283                                ));
 4284                                bracket_inserted = true;
 4285                                continue;
 4286                            }
 4287                        }
 4288
 4289                        if let Some(region) = autoclose_region {
 4290                            // If the selection is followed by an auto-inserted closing bracket,
 4291                            // then don't insert that closing bracket again; just move the selection
 4292                            // past the closing bracket.
 4293                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 4294                                && text.as_ref() == region.pair.end.as_str()
 4295                                && snapshot.contains_str_at(region.range.end, text.as_ref());
 4296                            if should_skip {
 4297                                let anchor = snapshot.anchor_after(selection.end);
 4298                                new_selections
 4299                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 4300                                continue;
 4301                            }
 4302                        }
 4303
 4304                        let always_treat_brackets_as_autoclosed = snapshot
 4305                            .language_settings_at(selection.start, cx)
 4306                            .always_treat_brackets_as_autoclosed;
 4307                        if always_treat_brackets_as_autoclosed
 4308                            && is_bracket_pair_end
 4309                            && snapshot.contains_str_at(selection.end, text.as_ref())
 4310                        {
 4311                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 4312                            // and the inserted text is a closing bracket and the selection is followed
 4313                            // by the closing bracket then move the selection past the closing bracket.
 4314                            let anchor = snapshot.anchor_after(selection.end);
 4315                            new_selections.push((selection.map(|_| anchor), text.len()));
 4316                            continue;
 4317                        }
 4318                    }
 4319                    // If an opening bracket is 1 character long and is typed while
 4320                    // text is selected, then surround that text with the bracket pair.
 4321                    else if auto_surround
 4322                        && bracket_pair.surround
 4323                        && is_bracket_pair_start
 4324                        && bracket_pair.start.chars().count() == 1
 4325                    {
 4326                        edits.push((selection.start..selection.start, text.clone()));
 4327                        edits.push((
 4328                            selection.end..selection.end,
 4329                            bracket_pair.end.as_str().into(),
 4330                        ));
 4331                        bracket_inserted = true;
 4332                        new_selections.push((
 4333                            Selection {
 4334                                id: selection.id,
 4335                                start: snapshot.anchor_after(selection.start),
 4336                                end: snapshot.anchor_before(selection.end),
 4337                                reversed: selection.reversed,
 4338                                goal: selection.goal,
 4339                            },
 4340                            0,
 4341                        ));
 4342                        continue;
 4343                    }
 4344                }
 4345            }
 4346
 4347            if self.auto_replace_emoji_shortcode
 4348                && selection.is_empty()
 4349                && text.as_ref().ends_with(':')
 4350                && let Some(possible_emoji_short_code) =
 4351                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 4352                && !possible_emoji_short_code.is_empty()
 4353                && let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code)
 4354            {
 4355                let emoji_shortcode_start = Point::new(
 4356                    selection.start.row,
 4357                    selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 4358                );
 4359
 4360                // Remove shortcode from buffer
 4361                edits.push((
 4362                    emoji_shortcode_start..selection.start,
 4363                    "".to_string().into(),
 4364                ));
 4365                new_selections.push((
 4366                    Selection {
 4367                        id: selection.id,
 4368                        start: snapshot.anchor_after(emoji_shortcode_start),
 4369                        end: snapshot.anchor_before(selection.start),
 4370                        reversed: selection.reversed,
 4371                        goal: selection.goal,
 4372                    },
 4373                    0,
 4374                ));
 4375
 4376                // Insert emoji
 4377                let selection_start_anchor = snapshot.anchor_after(selection.start);
 4378                new_selections.push((selection.map(|_| selection_start_anchor), 0));
 4379                edits.push((selection.start..selection.end, emoji.to_string().into()));
 4380
 4381                continue;
 4382            }
 4383
 4384            // If not handling any auto-close operation, then just replace the selected
 4385            // text with the given input and move the selection to the end of the
 4386            // newly inserted text.
 4387            let anchor = snapshot.anchor_after(selection.end);
 4388            if !self.linked_edit_ranges.is_empty() {
 4389                let start_anchor = snapshot.anchor_before(selection.start);
 4390
 4391                let is_word_char = text.chars().next().is_none_or(|char| {
 4392                    let classifier = snapshot
 4393                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 4394                        .scope_context(Some(CharScopeContext::LinkedEdit));
 4395                    classifier.is_word(char)
 4396                });
 4397
 4398                if is_word_char {
 4399                    if let Some(ranges) = self
 4400                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 4401                    {
 4402                        for (buffer, edits) in ranges {
 4403                            linked_edits
 4404                                .entry(buffer.clone())
 4405                                .or_default()
 4406                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 4407                        }
 4408                    }
 4409                } else {
 4410                    clear_linked_edit_ranges = true;
 4411                }
 4412            }
 4413
 4414            new_selections.push((selection.map(|_| anchor), 0));
 4415            edits.push((selection.start..selection.end, text.clone()));
 4416        }
 4417
 4418        drop(snapshot);
 4419
 4420        self.transact(window, cx, |this, window, cx| {
 4421            if clear_linked_edit_ranges {
 4422                this.linked_edit_ranges.clear();
 4423            }
 4424            let initial_buffer_versions =
 4425                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 4426
 4427            this.buffer.update(cx, |buffer, cx| {
 4428                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 4429            });
 4430            for (buffer, edits) in linked_edits {
 4431                buffer.update(cx, |buffer, cx| {
 4432                    let snapshot = buffer.snapshot();
 4433                    let edits = edits
 4434                        .into_iter()
 4435                        .map(|(range, text)| {
 4436                            use text::ToPoint as TP;
 4437                            let end_point = TP::to_point(&range.end, &snapshot);
 4438                            let start_point = TP::to_point(&range.start, &snapshot);
 4439                            (start_point..end_point, text)
 4440                        })
 4441                        .sorted_by_key(|(range, _)| range.start);
 4442                    buffer.edit(edits, None, cx);
 4443                })
 4444            }
 4445            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 4446            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 4447            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 4448            let new_selections =
 4449                resolve_selections_wrapping_blocks::<usize, _>(new_anchor_selections, &map)
 4450                    .zip(new_selection_deltas)
 4451                    .map(|(selection, delta)| Selection {
 4452                        id: selection.id,
 4453                        start: selection.start + delta,
 4454                        end: selection.end + delta,
 4455                        reversed: selection.reversed,
 4456                        goal: SelectionGoal::None,
 4457                    })
 4458                    .collect::<Vec<_>>();
 4459
 4460            let mut i = 0;
 4461            for (position, delta, selection_id, pair) in new_autoclose_regions {
 4462                let position = position.to_offset(map.buffer_snapshot()) + delta;
 4463                let start = map.buffer_snapshot().anchor_before(position);
 4464                let end = map.buffer_snapshot().anchor_after(position);
 4465                while let Some(existing_state) = this.autoclose_regions.get(i) {
 4466                    match existing_state
 4467                        .range
 4468                        .start
 4469                        .cmp(&start, map.buffer_snapshot())
 4470                    {
 4471                        Ordering::Less => i += 1,
 4472                        Ordering::Greater => break,
 4473                        Ordering::Equal => {
 4474                            match end.cmp(&existing_state.range.end, map.buffer_snapshot()) {
 4475                                Ordering::Less => i += 1,
 4476                                Ordering::Equal => break,
 4477                                Ordering::Greater => break,
 4478                            }
 4479                        }
 4480                    }
 4481                }
 4482                this.autoclose_regions.insert(
 4483                    i,
 4484                    AutocloseRegion {
 4485                        selection_id,
 4486                        range: start..end,
 4487                        pair,
 4488                    },
 4489                );
 4490            }
 4491
 4492            let had_active_edit_prediction = this.has_active_edit_prediction();
 4493            this.change_selections(
 4494                SelectionEffects::scroll(Autoscroll::fit()).completions(false),
 4495                window,
 4496                cx,
 4497                |s| s.select(new_selections),
 4498            );
 4499
 4500            if !bracket_inserted
 4501                && let Some(on_type_format_task) =
 4502                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 4503            {
 4504                on_type_format_task.detach_and_log_err(cx);
 4505            }
 4506
 4507            let editor_settings = EditorSettings::get_global(cx);
 4508            if bracket_inserted
 4509                && (editor_settings.auto_signature_help
 4510                    || editor_settings.show_signature_help_after_edits)
 4511            {
 4512                this.show_signature_help(&ShowSignatureHelp, window, cx);
 4513            }
 4514
 4515            let trigger_in_words =
 4516                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
 4517            if this.hard_wrap.is_some() {
 4518                let latest: Range<Point> = this.selections.newest(&map).range();
 4519                if latest.is_empty()
 4520                    && this
 4521                        .buffer()
 4522                        .read(cx)
 4523                        .snapshot(cx)
 4524                        .line_len(MultiBufferRow(latest.start.row))
 4525                        == latest.start.column
 4526                {
 4527                    this.rewrap_impl(
 4528                        RewrapOptions {
 4529                            override_language_settings: true,
 4530                            preserve_existing_whitespace: true,
 4531                        },
 4532                        cx,
 4533                    )
 4534                }
 4535            }
 4536            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4537            refresh_linked_ranges(this, window, cx);
 4538            this.refresh_edit_prediction(true, false, window, cx);
 4539            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4540        });
 4541    }
 4542
 4543    fn find_possible_emoji_shortcode_at_position(
 4544        snapshot: &MultiBufferSnapshot,
 4545        position: Point,
 4546    ) -> Option<String> {
 4547        let mut chars = Vec::new();
 4548        let mut found_colon = false;
 4549        for char in snapshot.reversed_chars_at(position).take(100) {
 4550            // Found a possible emoji shortcode in the middle of the buffer
 4551            if found_colon {
 4552                if char.is_whitespace() {
 4553                    chars.reverse();
 4554                    return Some(chars.iter().collect());
 4555                }
 4556                // If the previous character is not a whitespace, we are in the middle of a word
 4557                // and we only want to complete the shortcode if the word is made up of other emojis
 4558                let mut containing_word = String::new();
 4559                for ch in snapshot
 4560                    .reversed_chars_at(position)
 4561                    .skip(chars.len() + 1)
 4562                    .take(100)
 4563                {
 4564                    if ch.is_whitespace() {
 4565                        break;
 4566                    }
 4567                    containing_word.push(ch);
 4568                }
 4569                let containing_word = containing_word.chars().rev().collect::<String>();
 4570                if util::word_consists_of_emojis(containing_word.as_str()) {
 4571                    chars.reverse();
 4572                    return Some(chars.iter().collect());
 4573                }
 4574            }
 4575
 4576            if char.is_whitespace() || !char.is_ascii() {
 4577                return None;
 4578            }
 4579            if char == ':' {
 4580                found_colon = true;
 4581            } else {
 4582                chars.push(char);
 4583            }
 4584        }
 4585        // Found a possible emoji shortcode at the beginning of the buffer
 4586        chars.reverse();
 4587        Some(chars.iter().collect())
 4588    }
 4589
 4590    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4591        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4592        self.transact(window, cx, |this, window, cx| {
 4593            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4594                let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
 4595                let multi_buffer = this.buffer.read(cx);
 4596                let buffer = multi_buffer.snapshot(cx);
 4597                selections
 4598                    .iter()
 4599                    .map(|selection| {
 4600                        let start_point = selection.start.to_point(&buffer);
 4601                        let mut existing_indent =
 4602                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4603                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4604                        let start = selection.start;
 4605                        let end = selection.end;
 4606                        let selection_is_empty = start == end;
 4607                        let language_scope = buffer.language_scope_at(start);
 4608                        let (
 4609                            comment_delimiter,
 4610                            doc_delimiter,
 4611                            insert_extra_newline,
 4612                            indent_on_newline,
 4613                            indent_on_extra_newline,
 4614                        ) = if let Some(language) = &language_scope {
 4615                            let mut insert_extra_newline =
 4616                                insert_extra_newline_brackets(&buffer, start..end, language)
 4617                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 4618
 4619                            // Comment extension on newline is allowed only for cursor selections
 4620                            let comment_delimiter = maybe!({
 4621                                if !selection_is_empty {
 4622                                    return None;
 4623                                }
 4624
 4625                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4626                                    return None;
 4627                                }
 4628
 4629                                let delimiters = language.line_comment_prefixes();
 4630                                let max_len_of_delimiter =
 4631                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 4632                                let (snapshot, range) =
 4633                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4634
 4635                                let num_of_whitespaces = snapshot
 4636                                    .chars_for_range(range.clone())
 4637                                    .take_while(|c| c.is_whitespace())
 4638                                    .count();
 4639                                let comment_candidate = snapshot
 4640                                    .chars_for_range(range.clone())
 4641                                    .skip(num_of_whitespaces)
 4642                                    .take(max_len_of_delimiter)
 4643                                    .collect::<String>();
 4644                                let (delimiter, trimmed_len) = delimiters
 4645                                    .iter()
 4646                                    .filter_map(|delimiter| {
 4647                                        let prefix = delimiter.trim_end();
 4648                                        if comment_candidate.starts_with(prefix) {
 4649                                            Some((delimiter, prefix.len()))
 4650                                        } else {
 4651                                            None
 4652                                        }
 4653                                    })
 4654                                    .max_by_key(|(_, len)| *len)?;
 4655
 4656                                if let Some(BlockCommentConfig {
 4657                                    start: block_start, ..
 4658                                }) = language.block_comment()
 4659                                {
 4660                                    let block_start_trimmed = block_start.trim_end();
 4661                                    if block_start_trimmed.starts_with(delimiter.trim_end()) {
 4662                                        let line_content = snapshot
 4663                                            .chars_for_range(range)
 4664                                            .skip(num_of_whitespaces)
 4665                                            .take(block_start_trimmed.len())
 4666                                            .collect::<String>();
 4667
 4668                                        if line_content.starts_with(block_start_trimmed) {
 4669                                            return None;
 4670                                        }
 4671                                    }
 4672                                }
 4673
 4674                                let cursor_is_placed_after_comment_marker =
 4675                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 4676                                if cursor_is_placed_after_comment_marker {
 4677                                    Some(delimiter.clone())
 4678                                } else {
 4679                                    None
 4680                                }
 4681                            });
 4682
 4683                            let mut indent_on_newline = IndentSize::spaces(0);
 4684                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 4685
 4686                            let doc_delimiter = maybe!({
 4687                                if !selection_is_empty {
 4688                                    return None;
 4689                                }
 4690
 4691                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4692                                    return None;
 4693                                }
 4694
 4695                                let BlockCommentConfig {
 4696                                    start: start_tag,
 4697                                    end: end_tag,
 4698                                    prefix: delimiter,
 4699                                    tab_size: len,
 4700                                } = language.documentation_comment()?;
 4701                                let is_within_block_comment = buffer
 4702                                    .language_scope_at(start_point)
 4703                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4704                                if !is_within_block_comment {
 4705                                    return None;
 4706                                }
 4707
 4708                                let (snapshot, range) =
 4709                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4710
 4711                                let num_of_whitespaces = snapshot
 4712                                    .chars_for_range(range.clone())
 4713                                    .take_while(|c| c.is_whitespace())
 4714                                    .count();
 4715
 4716                                // 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.
 4717                                let column = start_point.column;
 4718                                let cursor_is_after_start_tag = {
 4719                                    let start_tag_len = start_tag.len();
 4720                                    let start_tag_line = snapshot
 4721                                        .chars_for_range(range.clone())
 4722                                        .skip(num_of_whitespaces)
 4723                                        .take(start_tag_len)
 4724                                        .collect::<String>();
 4725                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4726                                        num_of_whitespaces + start_tag_len <= column as usize
 4727                                    } else {
 4728                                        false
 4729                                    }
 4730                                };
 4731
 4732                                let cursor_is_after_delimiter = {
 4733                                    let delimiter_trim = delimiter.trim_end();
 4734                                    let delimiter_line = snapshot
 4735                                        .chars_for_range(range.clone())
 4736                                        .skip(num_of_whitespaces)
 4737                                        .take(delimiter_trim.len())
 4738                                        .collect::<String>();
 4739                                    if delimiter_line.starts_with(delimiter_trim) {
 4740                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4741                                    } else {
 4742                                        false
 4743                                    }
 4744                                };
 4745
 4746                                let cursor_is_before_end_tag_if_exists = {
 4747                                    let mut char_position = 0u32;
 4748                                    let mut end_tag_offset = None;
 4749
 4750                                    'outer: for chunk in snapshot.text_for_range(range) {
 4751                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4752                                            let chars_before_match =
 4753                                                chunk[..byte_pos].chars().count() as u32;
 4754                                            end_tag_offset =
 4755                                                Some(char_position + chars_before_match);
 4756                                            break 'outer;
 4757                                        }
 4758                                        char_position += chunk.chars().count() as u32;
 4759                                    }
 4760
 4761                                    if let Some(end_tag_offset) = end_tag_offset {
 4762                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4763                                        if cursor_is_after_start_tag {
 4764                                            if cursor_is_before_end_tag {
 4765                                                insert_extra_newline = true;
 4766                                            }
 4767                                            let cursor_is_at_start_of_end_tag =
 4768                                                column == end_tag_offset;
 4769                                            if cursor_is_at_start_of_end_tag {
 4770                                                indent_on_extra_newline.len = *len;
 4771                                            }
 4772                                        }
 4773                                        cursor_is_before_end_tag
 4774                                    } else {
 4775                                        true
 4776                                    }
 4777                                };
 4778
 4779                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4780                                    && cursor_is_before_end_tag_if_exists
 4781                                {
 4782                                    if cursor_is_after_start_tag {
 4783                                        indent_on_newline.len = *len;
 4784                                    }
 4785                                    Some(delimiter.clone())
 4786                                } else {
 4787                                    None
 4788                                }
 4789                            });
 4790
 4791                            (
 4792                                comment_delimiter,
 4793                                doc_delimiter,
 4794                                insert_extra_newline,
 4795                                indent_on_newline,
 4796                                indent_on_extra_newline,
 4797                            )
 4798                        } else {
 4799                            (
 4800                                None,
 4801                                None,
 4802                                false,
 4803                                IndentSize::default(),
 4804                                IndentSize::default(),
 4805                            )
 4806                        };
 4807
 4808                        let prevent_auto_indent = doc_delimiter.is_some();
 4809                        let delimiter = comment_delimiter.or(doc_delimiter);
 4810
 4811                        let capacity_for_delimiter =
 4812                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4813                        let mut new_text = String::with_capacity(
 4814                            1 + capacity_for_delimiter
 4815                                + existing_indent.len as usize
 4816                                + indent_on_newline.len as usize
 4817                                + indent_on_extra_newline.len as usize,
 4818                        );
 4819                        new_text.push('\n');
 4820                        new_text.extend(existing_indent.chars());
 4821                        new_text.extend(indent_on_newline.chars());
 4822
 4823                        if let Some(delimiter) = &delimiter {
 4824                            new_text.push_str(delimiter);
 4825                        }
 4826
 4827                        if insert_extra_newline {
 4828                            new_text.push('\n');
 4829                            new_text.extend(existing_indent.chars());
 4830                            new_text.extend(indent_on_extra_newline.chars());
 4831                        }
 4832
 4833                        let anchor = buffer.anchor_after(end);
 4834                        let new_selection = selection.map(|_| anchor);
 4835                        (
 4836                            ((start..end, new_text), prevent_auto_indent),
 4837                            (insert_extra_newline, new_selection),
 4838                        )
 4839                    })
 4840                    .unzip()
 4841            };
 4842
 4843            let mut auto_indent_edits = Vec::new();
 4844            let mut edits = Vec::new();
 4845            for (edit, prevent_auto_indent) in edits_with_flags {
 4846                if prevent_auto_indent {
 4847                    edits.push(edit);
 4848                } else {
 4849                    auto_indent_edits.push(edit);
 4850                }
 4851            }
 4852            if !edits.is_empty() {
 4853                this.edit(edits, cx);
 4854            }
 4855            if !auto_indent_edits.is_empty() {
 4856                this.edit_with_autoindent(auto_indent_edits, cx);
 4857            }
 4858
 4859            let buffer = this.buffer.read(cx).snapshot(cx);
 4860            let new_selections = selection_info
 4861                .into_iter()
 4862                .map(|(extra_newline_inserted, new_selection)| {
 4863                    let mut cursor = new_selection.end.to_point(&buffer);
 4864                    if extra_newline_inserted {
 4865                        cursor.row -= 1;
 4866                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4867                    }
 4868                    new_selection.map(|_| cursor)
 4869                })
 4870                .collect();
 4871
 4872            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
 4873            this.refresh_edit_prediction(true, false, window, cx);
 4874        });
 4875    }
 4876
 4877    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4878        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4879
 4880        let buffer = self.buffer.read(cx);
 4881        let snapshot = buffer.snapshot(cx);
 4882
 4883        let mut edits = Vec::new();
 4884        let mut rows = Vec::new();
 4885
 4886        for (rows_inserted, selection) in self
 4887            .selections
 4888            .all_adjusted(&self.display_snapshot(cx))
 4889            .into_iter()
 4890            .enumerate()
 4891        {
 4892            let cursor = selection.head();
 4893            let row = cursor.row;
 4894
 4895            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4896
 4897            let newline = "\n".to_string();
 4898            edits.push((start_of_line..start_of_line, newline));
 4899
 4900            rows.push(row + rows_inserted as u32);
 4901        }
 4902
 4903        self.transact(window, cx, |editor, window, cx| {
 4904            editor.edit(edits, cx);
 4905
 4906            editor.change_selections(Default::default(), window, cx, |s| {
 4907                let mut index = 0;
 4908                s.move_cursors_with(|map, _, _| {
 4909                    let row = rows[index];
 4910                    index += 1;
 4911
 4912                    let point = Point::new(row, 0);
 4913                    let boundary = map.next_line_boundary(point).1;
 4914                    let clipped = map.clip_point(boundary, Bias::Left);
 4915
 4916                    (clipped, SelectionGoal::None)
 4917                });
 4918            });
 4919
 4920            let mut indent_edits = Vec::new();
 4921            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4922            for row in rows {
 4923                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4924                for (row, indent) in indents {
 4925                    if indent.len == 0 {
 4926                        continue;
 4927                    }
 4928
 4929                    let text = match indent.kind {
 4930                        IndentKind::Space => " ".repeat(indent.len as usize),
 4931                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4932                    };
 4933                    let point = Point::new(row.0, 0);
 4934                    indent_edits.push((point..point, text));
 4935                }
 4936            }
 4937            editor.edit(indent_edits, cx);
 4938        });
 4939    }
 4940
 4941    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 4942        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4943
 4944        let buffer = self.buffer.read(cx);
 4945        let snapshot = buffer.snapshot(cx);
 4946
 4947        let mut edits = Vec::new();
 4948        let mut rows = Vec::new();
 4949        let mut rows_inserted = 0;
 4950
 4951        for selection in self.selections.all_adjusted(&self.display_snapshot(cx)) {
 4952            let cursor = selection.head();
 4953            let row = cursor.row;
 4954
 4955            let point = Point::new(row + 1, 0);
 4956            let start_of_line = snapshot.clip_point(point, Bias::Left);
 4957
 4958            let newline = "\n".to_string();
 4959            edits.push((start_of_line..start_of_line, newline));
 4960
 4961            rows_inserted += 1;
 4962            rows.push(row + rows_inserted);
 4963        }
 4964
 4965        self.transact(window, cx, |editor, window, cx| {
 4966            editor.edit(edits, cx);
 4967
 4968            editor.change_selections(Default::default(), window, cx, |s| {
 4969                let mut index = 0;
 4970                s.move_cursors_with(|map, _, _| {
 4971                    let row = rows[index];
 4972                    index += 1;
 4973
 4974                    let point = Point::new(row, 0);
 4975                    let boundary = map.next_line_boundary(point).1;
 4976                    let clipped = map.clip_point(boundary, Bias::Left);
 4977
 4978                    (clipped, SelectionGoal::None)
 4979                });
 4980            });
 4981
 4982            let mut indent_edits = Vec::new();
 4983            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4984            for row in rows {
 4985                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4986                for (row, indent) in indents {
 4987                    if indent.len == 0 {
 4988                        continue;
 4989                    }
 4990
 4991                    let text = match indent.kind {
 4992                        IndentKind::Space => " ".repeat(indent.len as usize),
 4993                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4994                    };
 4995                    let point = Point::new(row.0, 0);
 4996                    indent_edits.push((point..point, text));
 4997                }
 4998            }
 4999            editor.edit(indent_edits, cx);
 5000        });
 5001    }
 5002
 5003    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 5004        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 5005            original_indent_columns: Vec::new(),
 5006        });
 5007        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 5008    }
 5009
 5010    fn insert_with_autoindent_mode(
 5011        &mut self,
 5012        text: &str,
 5013        autoindent_mode: Option<AutoindentMode>,
 5014        window: &mut Window,
 5015        cx: &mut Context<Self>,
 5016    ) {
 5017        if self.read_only(cx) {
 5018            return;
 5019        }
 5020
 5021        let text: Arc<str> = text.into();
 5022        self.transact(window, cx, |this, window, cx| {
 5023            let old_selections = this.selections.all_adjusted(&this.display_snapshot(cx));
 5024            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 5025                let anchors = {
 5026                    let snapshot = buffer.read(cx);
 5027                    old_selections
 5028                        .iter()
 5029                        .map(|s| {
 5030                            let anchor = snapshot.anchor_after(s.head());
 5031                            s.map(|_| anchor)
 5032                        })
 5033                        .collect::<Vec<_>>()
 5034                };
 5035                buffer.edit(
 5036                    old_selections
 5037                        .iter()
 5038                        .map(|s| (s.start..s.end, text.clone())),
 5039                    autoindent_mode,
 5040                    cx,
 5041                );
 5042                anchors
 5043            });
 5044
 5045            this.change_selections(Default::default(), window, cx, |s| {
 5046                s.select_anchors(selection_anchors);
 5047            });
 5048
 5049            cx.notify();
 5050        });
 5051    }
 5052
 5053    fn trigger_completion_on_input(
 5054        &mut self,
 5055        text: &str,
 5056        trigger_in_words: bool,
 5057        window: &mut Window,
 5058        cx: &mut Context<Self>,
 5059    ) {
 5060        let completions_source = self
 5061            .context_menu
 5062            .borrow()
 5063            .as_ref()
 5064            .and_then(|menu| match menu {
 5065                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 5066                CodeContextMenu::CodeActions(_) => None,
 5067            });
 5068
 5069        match completions_source {
 5070            Some(CompletionsMenuSource::Words { .. }) => {
 5071                self.open_or_update_completions_menu(
 5072                    Some(CompletionsMenuSource::Words {
 5073                        ignore_threshold: false,
 5074                    }),
 5075                    None,
 5076                    window,
 5077                    cx,
 5078                );
 5079            }
 5080            Some(CompletionsMenuSource::Normal)
 5081            | Some(CompletionsMenuSource::SnippetChoices)
 5082            | None
 5083                if self.is_completion_trigger(
 5084                    text,
 5085                    trigger_in_words,
 5086                    completions_source.is_some(),
 5087                    cx,
 5088                ) =>
 5089            {
 5090                self.show_completions(
 5091                    &ShowCompletions {
 5092                        trigger: Some(text.to_owned()).filter(|x| !x.is_empty()),
 5093                    },
 5094                    window,
 5095                    cx,
 5096                )
 5097            }
 5098            _ => {
 5099                self.hide_context_menu(window, cx);
 5100            }
 5101        }
 5102    }
 5103
 5104    fn is_completion_trigger(
 5105        &self,
 5106        text: &str,
 5107        trigger_in_words: bool,
 5108        menu_is_open: bool,
 5109        cx: &mut Context<Self>,
 5110    ) -> bool {
 5111        let position = self.selections.newest_anchor().head();
 5112        let Some(buffer) = self.buffer.read(cx).buffer_for_anchor(position, cx) else {
 5113            return false;
 5114        };
 5115
 5116        if let Some(completion_provider) = &self.completion_provider {
 5117            completion_provider.is_completion_trigger(
 5118                &buffer,
 5119                position.text_anchor,
 5120                text,
 5121                trigger_in_words,
 5122                menu_is_open,
 5123                cx,
 5124            )
 5125        } else {
 5126            false
 5127        }
 5128    }
 5129
 5130    /// If any empty selections is touching the start of its innermost containing autoclose
 5131    /// region, expand it to select the brackets.
 5132    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 5133        let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
 5134        let buffer = self.buffer.read(cx).read(cx);
 5135        let new_selections = self
 5136            .selections_with_autoclose_regions(selections, &buffer)
 5137            .map(|(mut selection, region)| {
 5138                if !selection.is_empty() {
 5139                    return selection;
 5140                }
 5141
 5142                if let Some(region) = region {
 5143                    let mut range = region.range.to_offset(&buffer);
 5144                    if selection.start == range.start && range.start >= region.pair.start.len() {
 5145                        range.start -= region.pair.start.len();
 5146                        if buffer.contains_str_at(range.start, &region.pair.start)
 5147                            && buffer.contains_str_at(range.end, &region.pair.end)
 5148                        {
 5149                            range.end += region.pair.end.len();
 5150                            selection.start = range.start;
 5151                            selection.end = range.end;
 5152
 5153                            return selection;
 5154                        }
 5155                    }
 5156                }
 5157
 5158                let always_treat_brackets_as_autoclosed = buffer
 5159                    .language_settings_at(selection.start, cx)
 5160                    .always_treat_brackets_as_autoclosed;
 5161
 5162                if !always_treat_brackets_as_autoclosed {
 5163                    return selection;
 5164                }
 5165
 5166                if let Some(scope) = buffer.language_scope_at(selection.start) {
 5167                    for (pair, enabled) in scope.brackets() {
 5168                        if !enabled || !pair.close {
 5169                            continue;
 5170                        }
 5171
 5172                        if buffer.contains_str_at(selection.start, &pair.end) {
 5173                            let pair_start_len = pair.start.len();
 5174                            if buffer.contains_str_at(
 5175                                selection.start.saturating_sub(pair_start_len),
 5176                                &pair.start,
 5177                            ) {
 5178                                selection.start -= pair_start_len;
 5179                                selection.end += pair.end.len();
 5180
 5181                                return selection;
 5182                            }
 5183                        }
 5184                    }
 5185                }
 5186
 5187                selection
 5188            })
 5189            .collect();
 5190
 5191        drop(buffer);
 5192        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
 5193            selections.select(new_selections)
 5194        });
 5195    }
 5196
 5197    /// Iterate the given selections, and for each one, find the smallest surrounding
 5198    /// autoclose region. This uses the ordering of the selections and the autoclose
 5199    /// regions to avoid repeated comparisons.
 5200    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 5201        &'a self,
 5202        selections: impl IntoIterator<Item = Selection<D>>,
 5203        buffer: &'a MultiBufferSnapshot,
 5204    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 5205        let mut i = 0;
 5206        let mut regions = self.autoclose_regions.as_slice();
 5207        selections.into_iter().map(move |selection| {
 5208            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 5209
 5210            let mut enclosing = None;
 5211            while let Some(pair_state) = regions.get(i) {
 5212                if pair_state.range.end.to_offset(buffer) < range.start {
 5213                    regions = &regions[i + 1..];
 5214                    i = 0;
 5215                } else if pair_state.range.start.to_offset(buffer) > range.end {
 5216                    break;
 5217                } else {
 5218                    if pair_state.selection_id == selection.id {
 5219                        enclosing = Some(pair_state);
 5220                    }
 5221                    i += 1;
 5222                }
 5223            }
 5224
 5225            (selection, enclosing)
 5226        })
 5227    }
 5228
 5229    /// Remove any autoclose regions that no longer contain their selection or have invalid anchors in ranges.
 5230    fn invalidate_autoclose_regions(
 5231        &mut self,
 5232        mut selections: &[Selection<Anchor>],
 5233        buffer: &MultiBufferSnapshot,
 5234    ) {
 5235        self.autoclose_regions.retain(|state| {
 5236            if !state.range.start.is_valid(buffer) || !state.range.end.is_valid(buffer) {
 5237                return false;
 5238            }
 5239
 5240            let mut i = 0;
 5241            while let Some(selection) = selections.get(i) {
 5242                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 5243                    selections = &selections[1..];
 5244                    continue;
 5245                }
 5246                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 5247                    break;
 5248                }
 5249                if selection.id == state.selection_id {
 5250                    return true;
 5251                } else {
 5252                    i += 1;
 5253                }
 5254            }
 5255            false
 5256        });
 5257    }
 5258
 5259    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 5260        let offset = position.to_offset(buffer);
 5261        let (word_range, kind) =
 5262            buffer.surrounding_word(offset, Some(CharScopeContext::Completion));
 5263        if offset > word_range.start && kind == Some(CharKind::Word) {
 5264            Some(
 5265                buffer
 5266                    .text_for_range(word_range.start..offset)
 5267                    .collect::<String>(),
 5268            )
 5269        } else {
 5270            None
 5271        }
 5272    }
 5273
 5274    pub fn visible_excerpts(
 5275        &self,
 5276        cx: &mut Context<Editor>,
 5277    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 5278        let Some(project) = self.project() else {
 5279            return HashMap::default();
 5280        };
 5281        let project = project.read(cx);
 5282        let multi_buffer = self.buffer().read(cx);
 5283        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 5284        let multi_buffer_visible_start = self
 5285            .scroll_manager
 5286            .anchor()
 5287            .anchor
 5288            .to_point(&multi_buffer_snapshot);
 5289        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 5290            multi_buffer_visible_start
 5291                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 5292            Bias::Left,
 5293        );
 5294        multi_buffer_snapshot
 5295            .range_to_buffer_ranges(multi_buffer_visible_start..multi_buffer_visible_end)
 5296            .into_iter()
 5297            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 5298            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 5299                let buffer_file = project::File::from_dyn(buffer.file())?;
 5300                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 5301                let worktree_entry = buffer_worktree
 5302                    .read(cx)
 5303                    .entry_for_id(buffer_file.project_entry_id()?)?;
 5304                if worktree_entry.is_ignored {
 5305                    None
 5306                } else {
 5307                    Some((
 5308                        excerpt_id,
 5309                        (
 5310                            multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5311                            buffer.version().clone(),
 5312                            excerpt_visible_range,
 5313                        ),
 5314                    ))
 5315                }
 5316            })
 5317            .collect()
 5318    }
 5319
 5320    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 5321        TextLayoutDetails {
 5322            text_system: window.text_system().clone(),
 5323            editor_style: self.style.clone().unwrap(),
 5324            rem_size: window.rem_size(),
 5325            scroll_anchor: self.scroll_manager.anchor(),
 5326            visible_rows: self.visible_line_count(),
 5327            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 5328        }
 5329    }
 5330
 5331    fn trigger_on_type_formatting(
 5332        &self,
 5333        input: String,
 5334        window: &mut Window,
 5335        cx: &mut Context<Self>,
 5336    ) -> Option<Task<Result<()>>> {
 5337        if input.len() != 1 {
 5338            return None;
 5339        }
 5340
 5341        let project = self.project()?;
 5342        let position = self.selections.newest_anchor().head();
 5343        let (buffer, buffer_position) = self
 5344            .buffer
 5345            .read(cx)
 5346            .text_anchor_for_position(position, cx)?;
 5347
 5348        let settings = language_settings::language_settings(
 5349            buffer
 5350                .read(cx)
 5351                .language_at(buffer_position)
 5352                .map(|l| l.name()),
 5353            buffer.read(cx).file(),
 5354            cx,
 5355        );
 5356        if !settings.use_on_type_format {
 5357            return None;
 5358        }
 5359
 5360        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5361        // hence we do LSP request & edit on host side only — add formats to host's history.
 5362        let push_to_lsp_host_history = true;
 5363        // If this is not the host, append its history with new edits.
 5364        let push_to_client_history = project.read(cx).is_via_collab();
 5365
 5366        let on_type_formatting = project.update(cx, |project, cx| {
 5367            project.on_type_format(
 5368                buffer.clone(),
 5369                buffer_position,
 5370                input,
 5371                push_to_lsp_host_history,
 5372                cx,
 5373            )
 5374        });
 5375        Some(cx.spawn_in(window, async move |editor, cx| {
 5376            if let Some(transaction) = on_type_formatting.await? {
 5377                if push_to_client_history {
 5378                    buffer
 5379                        .update(cx, |buffer, _| {
 5380                            buffer.push_transaction(transaction, Instant::now());
 5381                            buffer.finalize_last_transaction();
 5382                        })
 5383                        .ok();
 5384                }
 5385                editor.update(cx, |editor, cx| {
 5386                    editor.refresh_document_highlights(cx);
 5387                })?;
 5388            }
 5389            Ok(())
 5390        }))
 5391    }
 5392
 5393    pub fn show_word_completions(
 5394        &mut self,
 5395        _: &ShowWordCompletions,
 5396        window: &mut Window,
 5397        cx: &mut Context<Self>,
 5398    ) {
 5399        self.open_or_update_completions_menu(
 5400            Some(CompletionsMenuSource::Words {
 5401                ignore_threshold: true,
 5402            }),
 5403            None,
 5404            window,
 5405            cx,
 5406        );
 5407    }
 5408
 5409    pub fn show_completions(
 5410        &mut self,
 5411        options: &ShowCompletions,
 5412        window: &mut Window,
 5413        cx: &mut Context<Self>,
 5414    ) {
 5415        self.open_or_update_completions_menu(None, options.trigger.as_deref(), window, cx);
 5416    }
 5417
 5418    fn open_or_update_completions_menu(
 5419        &mut self,
 5420        requested_source: Option<CompletionsMenuSource>,
 5421        trigger: Option<&str>,
 5422        window: &mut Window,
 5423        cx: &mut Context<Self>,
 5424    ) {
 5425        if self.pending_rename.is_some() {
 5426            return;
 5427        }
 5428
 5429        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5430
 5431        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5432        // inserted and selected. To handle that case, the start of the selection is used so that
 5433        // the menu starts with all choices.
 5434        let position = self
 5435            .selections
 5436            .newest_anchor()
 5437            .start
 5438            .bias_right(&multibuffer_snapshot);
 5439        if position.diff_base_anchor.is_some() {
 5440            return;
 5441        }
 5442        let buffer_position = multibuffer_snapshot.anchor_before(position);
 5443        let Some(buffer) = buffer_position
 5444            .buffer_id
 5445            .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
 5446        else {
 5447            return;
 5448        };
 5449        let buffer_snapshot = buffer.read(cx).snapshot();
 5450
 5451        let query: Option<Arc<String>> =
 5452            Self::completion_query(&multibuffer_snapshot, buffer_position)
 5453                .map(|query| query.into());
 5454
 5455        drop(multibuffer_snapshot);
 5456
 5457        // Hide the current completions menu when query is empty. Without this, cached
 5458        // completions from before the trigger char may be reused (#32774).
 5459        if query.is_none() {
 5460            let menu_is_open = matches!(
 5461                self.context_menu.borrow().as_ref(),
 5462                Some(CodeContextMenu::Completions(_))
 5463            );
 5464            if menu_is_open {
 5465                self.hide_context_menu(window, cx);
 5466            }
 5467        }
 5468
 5469        let mut ignore_word_threshold = false;
 5470        let provider = match requested_source {
 5471            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5472            Some(CompletionsMenuSource::Words { ignore_threshold }) => {
 5473                ignore_word_threshold = ignore_threshold;
 5474                None
 5475            }
 5476            Some(CompletionsMenuSource::SnippetChoices) => {
 5477                log::error!("bug: SnippetChoices requested_source is not handled");
 5478                None
 5479            }
 5480        };
 5481
 5482        let sort_completions = provider
 5483            .as_ref()
 5484            .is_some_and(|provider| provider.sort_completions());
 5485
 5486        let filter_completions = provider
 5487            .as_ref()
 5488            .is_none_or(|provider| provider.filter_completions());
 5489
 5490        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5491            if filter_completions {
 5492                menu.filter(query.clone(), provider.clone(), window, cx);
 5493            }
 5494            // When `is_incomplete` is false, no need to re-query completions when the current query
 5495            // is a suffix of the initial query.
 5496            if !menu.is_incomplete {
 5497                // If the new query is a suffix of the old query (typing more characters) and
 5498                // the previous result was complete, the existing completions can be filtered.
 5499                //
 5500                // Note that this is always true for snippet completions.
 5501                let query_matches = match (&menu.initial_query, &query) {
 5502                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5503                    (None, _) => true,
 5504                    _ => false,
 5505                };
 5506                if query_matches {
 5507                    let position_matches = if menu.initial_position == position {
 5508                        true
 5509                    } else {
 5510                        let snapshot = self.buffer.read(cx).read(cx);
 5511                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5512                    };
 5513                    if position_matches {
 5514                        return;
 5515                    }
 5516                }
 5517            }
 5518        };
 5519
 5520        let trigger_kind = match trigger {
 5521            Some(trigger) if buffer.read(cx).completion_triggers().contains(trigger) => {
 5522                CompletionTriggerKind::TRIGGER_CHARACTER
 5523            }
 5524            _ => CompletionTriggerKind::INVOKED,
 5525        };
 5526        let completion_context = CompletionContext {
 5527            trigger_character: trigger.and_then(|trigger| {
 5528                if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER {
 5529                    Some(String::from(trigger))
 5530                } else {
 5531                    None
 5532                }
 5533            }),
 5534            trigger_kind,
 5535        };
 5536
 5537        let Anchor {
 5538            excerpt_id: buffer_excerpt_id,
 5539            text_anchor: buffer_position,
 5540            ..
 5541        } = buffer_position;
 5542
 5543        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5544            buffer_snapshot.surrounding_word(buffer_position, None)
 5545        {
 5546            let word_to_exclude = buffer_snapshot
 5547                .text_for_range(word_range.clone())
 5548                .collect::<String>();
 5549            (
 5550                buffer_snapshot.anchor_before(word_range.start)
 5551                    ..buffer_snapshot.anchor_after(buffer_position),
 5552                Some(word_to_exclude),
 5553            )
 5554        } else {
 5555            (buffer_position..buffer_position, None)
 5556        };
 5557
 5558        let language = buffer_snapshot
 5559            .language_at(buffer_position)
 5560            .map(|language| language.name());
 5561
 5562        let completion_settings = language_settings(language.clone(), buffer_snapshot.file(), cx)
 5563            .completions
 5564            .clone();
 5565
 5566        let show_completion_documentation = buffer_snapshot
 5567            .settings_at(buffer_position, cx)
 5568            .show_completion_documentation;
 5569
 5570        // The document can be large, so stay in reasonable bounds when searching for words,
 5571        // otherwise completion pop-up might be slow to appear.
 5572        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5573        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5574        let min_word_search = buffer_snapshot.clip_point(
 5575            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5576            Bias::Left,
 5577        );
 5578        let max_word_search = buffer_snapshot.clip_point(
 5579            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5580            Bias::Right,
 5581        );
 5582        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5583            ..buffer_snapshot.point_to_offset(max_word_search);
 5584
 5585        let skip_digits = query
 5586            .as_ref()
 5587            .is_none_or(|query| !query.chars().any(|c| c.is_digit(10)));
 5588
 5589        let omit_word_completions = !self.word_completions_enabled
 5590            || (!ignore_word_threshold
 5591                && match &query {
 5592                    Some(query) => query.chars().count() < completion_settings.words_min_length,
 5593                    None => completion_settings.words_min_length != 0,
 5594                });
 5595
 5596        let (mut words, provider_responses) = match &provider {
 5597            Some(provider) => {
 5598                let provider_responses = provider.completions(
 5599                    buffer_excerpt_id,
 5600                    &buffer,
 5601                    buffer_position,
 5602                    completion_context,
 5603                    window,
 5604                    cx,
 5605                );
 5606
 5607                let words = match (omit_word_completions, completion_settings.words) {
 5608                    (true, _) | (_, WordsCompletionMode::Disabled) => {
 5609                        Task::ready(BTreeMap::default())
 5610                    }
 5611                    (false, WordsCompletionMode::Enabled | WordsCompletionMode::Fallback) => cx
 5612                        .background_spawn(async move {
 5613                            buffer_snapshot.words_in_range(WordsQuery {
 5614                                fuzzy_contents: None,
 5615                                range: word_search_range,
 5616                                skip_digits,
 5617                            })
 5618                        }),
 5619                };
 5620
 5621                (words, provider_responses)
 5622            }
 5623            None => {
 5624                let words = if omit_word_completions {
 5625                    Task::ready(BTreeMap::default())
 5626                } else {
 5627                    cx.background_spawn(async move {
 5628                        buffer_snapshot.words_in_range(WordsQuery {
 5629                            fuzzy_contents: None,
 5630                            range: word_search_range,
 5631                            skip_digits,
 5632                        })
 5633                    })
 5634                };
 5635                (words, Task::ready(Ok(Vec::new())))
 5636            }
 5637        };
 5638
 5639        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5640
 5641        let id = post_inc(&mut self.next_completion_id);
 5642        let task = cx.spawn_in(window, async move |editor, cx| {
 5643            let Ok(()) = editor.update(cx, |this, _| {
 5644                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5645            }) else {
 5646                return;
 5647            };
 5648
 5649            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5650            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5651            let mut completions = Vec::new();
 5652            let mut is_incomplete = false;
 5653            let mut display_options: Option<CompletionDisplayOptions> = None;
 5654            if let Some(provider_responses) = provider_responses.await.log_err()
 5655                && !provider_responses.is_empty()
 5656            {
 5657                for response in provider_responses {
 5658                    completions.extend(response.completions);
 5659                    is_incomplete = is_incomplete || response.is_incomplete;
 5660                    match display_options.as_mut() {
 5661                        None => {
 5662                            display_options = Some(response.display_options);
 5663                        }
 5664                        Some(options) => options.merge(&response.display_options),
 5665                    }
 5666                }
 5667                if completion_settings.words == WordsCompletionMode::Fallback {
 5668                    words = Task::ready(BTreeMap::default());
 5669                }
 5670            }
 5671            let display_options = display_options.unwrap_or_default();
 5672
 5673            let mut words = words.await;
 5674            if let Some(word_to_exclude) = &word_to_exclude {
 5675                words.remove(word_to_exclude);
 5676            }
 5677            for lsp_completion in &completions {
 5678                words.remove(&lsp_completion.new_text);
 5679            }
 5680            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5681                replace_range: word_replace_range.clone(),
 5682                new_text: word.clone(),
 5683                label: CodeLabel::plain(word, None),
 5684                icon_path: None,
 5685                documentation: None,
 5686                source: CompletionSource::BufferWord {
 5687                    word_range,
 5688                    resolved: false,
 5689                },
 5690                insert_text_mode: Some(InsertTextMode::AS_IS),
 5691                confirm: None,
 5692            }));
 5693
 5694            let menu = if completions.is_empty() {
 5695                None
 5696            } else {
 5697                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5698                    let languages = editor
 5699                        .workspace
 5700                        .as_ref()
 5701                        .and_then(|(workspace, _)| workspace.upgrade())
 5702                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5703                    let menu = CompletionsMenu::new(
 5704                        id,
 5705                        requested_source.unwrap_or(CompletionsMenuSource::Normal),
 5706                        sort_completions,
 5707                        show_completion_documentation,
 5708                        position,
 5709                        query.clone(),
 5710                        is_incomplete,
 5711                        buffer.clone(),
 5712                        completions.into(),
 5713                        display_options,
 5714                        snippet_sort_order,
 5715                        languages,
 5716                        language,
 5717                        cx,
 5718                    );
 5719
 5720                    let query = if filter_completions { query } else { None };
 5721                    let matches_task = if let Some(query) = query {
 5722                        menu.do_async_filtering(query, cx)
 5723                    } else {
 5724                        Task::ready(menu.unfiltered_matches())
 5725                    };
 5726                    (menu, matches_task)
 5727                }) else {
 5728                    return;
 5729                };
 5730
 5731                let matches = matches_task.await;
 5732
 5733                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5734                    // Newer menu already set, so exit.
 5735                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5736                        editor.context_menu.borrow().as_ref()
 5737                        && prev_menu.id > id
 5738                    {
 5739                        return;
 5740                    };
 5741
 5742                    // Only valid to take prev_menu because it the new menu is immediately set
 5743                    // below, or the menu is hidden.
 5744                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5745                        editor.context_menu.borrow_mut().take()
 5746                    {
 5747                        let position_matches =
 5748                            if prev_menu.initial_position == menu.initial_position {
 5749                                true
 5750                            } else {
 5751                                let snapshot = editor.buffer.read(cx).read(cx);
 5752                                prev_menu.initial_position.to_offset(&snapshot)
 5753                                    == menu.initial_position.to_offset(&snapshot)
 5754                            };
 5755                        if position_matches {
 5756                            // Preserve markdown cache before `set_filter_results` because it will
 5757                            // try to populate the documentation cache.
 5758                            menu.preserve_markdown_cache(prev_menu);
 5759                        }
 5760                    };
 5761
 5762                    menu.set_filter_results(matches, provider, window, cx);
 5763                }) else {
 5764                    return;
 5765                };
 5766
 5767                menu.visible().then_some(menu)
 5768            };
 5769
 5770            editor
 5771                .update_in(cx, |editor, window, cx| {
 5772                    if editor.focus_handle.is_focused(window)
 5773                        && let Some(menu) = menu
 5774                    {
 5775                        *editor.context_menu.borrow_mut() =
 5776                            Some(CodeContextMenu::Completions(menu));
 5777
 5778                        crate::hover_popover::hide_hover(editor, cx);
 5779                        if editor.show_edit_predictions_in_menu() {
 5780                            editor.update_visible_edit_prediction(window, cx);
 5781                        } else {
 5782                            editor.discard_edit_prediction(false, cx);
 5783                        }
 5784
 5785                        cx.notify();
 5786                        return;
 5787                    }
 5788
 5789                    if editor.completion_tasks.len() <= 1 {
 5790                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 5791                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5792                        // If it was already hidden and we don't show edit predictions in the menu,
 5793                        // we should also show the edit prediction when available.
 5794                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5795                            editor.update_visible_edit_prediction(window, cx);
 5796                        }
 5797                    }
 5798                })
 5799                .ok();
 5800        });
 5801
 5802        self.completion_tasks.push((id, task));
 5803    }
 5804
 5805    #[cfg(feature = "test-support")]
 5806    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5807        let menu = self.context_menu.borrow();
 5808        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5809            let completions = menu.completions.borrow();
 5810            Some(completions.to_vec())
 5811        } else {
 5812            None
 5813        }
 5814    }
 5815
 5816    pub fn with_completions_menu_matching_id<R>(
 5817        &self,
 5818        id: CompletionId,
 5819        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 5820    ) -> R {
 5821        let mut context_menu = self.context_menu.borrow_mut();
 5822        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 5823            return f(None);
 5824        };
 5825        if completions_menu.id != id {
 5826            return f(None);
 5827        }
 5828        f(Some(completions_menu))
 5829    }
 5830
 5831    pub fn confirm_completion(
 5832        &mut self,
 5833        action: &ConfirmCompletion,
 5834        window: &mut Window,
 5835        cx: &mut Context<Self>,
 5836    ) -> Option<Task<Result<()>>> {
 5837        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5838        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5839    }
 5840
 5841    pub fn confirm_completion_insert(
 5842        &mut self,
 5843        _: &ConfirmCompletionInsert,
 5844        window: &mut Window,
 5845        cx: &mut Context<Self>,
 5846    ) -> Option<Task<Result<()>>> {
 5847        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5848        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5849    }
 5850
 5851    pub fn confirm_completion_replace(
 5852        &mut self,
 5853        _: &ConfirmCompletionReplace,
 5854        window: &mut Window,
 5855        cx: &mut Context<Self>,
 5856    ) -> Option<Task<Result<()>>> {
 5857        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5858        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5859    }
 5860
 5861    pub fn compose_completion(
 5862        &mut self,
 5863        action: &ComposeCompletion,
 5864        window: &mut Window,
 5865        cx: &mut Context<Self>,
 5866    ) -> Option<Task<Result<()>>> {
 5867        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5868        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5869    }
 5870
 5871    fn do_completion(
 5872        &mut self,
 5873        item_ix: Option<usize>,
 5874        intent: CompletionIntent,
 5875        window: &mut Window,
 5876        cx: &mut Context<Editor>,
 5877    ) -> Option<Task<Result<()>>> {
 5878        use language::ToOffset as _;
 5879
 5880        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5881        else {
 5882            return None;
 5883        };
 5884
 5885        let candidate_id = {
 5886            let entries = completions_menu.entries.borrow();
 5887            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5888            if self.show_edit_predictions_in_menu() {
 5889                self.discard_edit_prediction(true, cx);
 5890            }
 5891            mat.candidate_id
 5892        };
 5893
 5894        let completion = completions_menu
 5895            .completions
 5896            .borrow()
 5897            .get(candidate_id)?
 5898            .clone();
 5899        cx.stop_propagation();
 5900
 5901        let buffer_handle = completions_menu.buffer.clone();
 5902
 5903        let CompletionEdit {
 5904            new_text,
 5905            snippet,
 5906            replace_range,
 5907        } = process_completion_for_edit(
 5908            &completion,
 5909            intent,
 5910            &buffer_handle,
 5911            &completions_menu.initial_position.text_anchor,
 5912            cx,
 5913        );
 5914
 5915        let buffer = buffer_handle.read(cx);
 5916        let snapshot = self.buffer.read(cx).snapshot(cx);
 5917        let newest_anchor = self.selections.newest_anchor();
 5918        let replace_range_multibuffer = {
 5919            let mut excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 5920            excerpt.map_range_from_buffer(replace_range.clone())
 5921        };
 5922        if snapshot.buffer_id_for_anchor(newest_anchor.head()) != Some(buffer.remote_id()) {
 5923            return None;
 5924        }
 5925
 5926        let old_text = buffer
 5927            .text_for_range(replace_range.clone())
 5928            .collect::<String>();
 5929        let lookbehind = newest_anchor
 5930            .start
 5931            .text_anchor
 5932            .to_offset(buffer)
 5933            .saturating_sub(replace_range.start);
 5934        let lookahead = replace_range
 5935            .end
 5936            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 5937        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 5938        let suffix = &old_text[lookbehind.min(old_text.len())..];
 5939
 5940        let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
 5941        let mut ranges = Vec::new();
 5942        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 5943
 5944        for selection in &selections {
 5945            let range = if selection.id == newest_anchor.id {
 5946                replace_range_multibuffer.clone()
 5947            } else {
 5948                let mut range = selection.range();
 5949
 5950                // if prefix is present, don't duplicate it
 5951                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 5952                    range.start = range.start.saturating_sub(lookbehind);
 5953
 5954                    // if suffix is also present, mimic the newest cursor and replace it
 5955                    if selection.id != newest_anchor.id
 5956                        && snapshot.contains_str_at(range.end, suffix)
 5957                    {
 5958                        range.end += lookahead;
 5959                    }
 5960                }
 5961                range
 5962            };
 5963
 5964            ranges.push(range.clone());
 5965
 5966            if !self.linked_edit_ranges.is_empty() {
 5967                let start_anchor = snapshot.anchor_before(range.start);
 5968                let end_anchor = snapshot.anchor_after(range.end);
 5969                if let Some(ranges) = self
 5970                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 5971                {
 5972                    for (buffer, edits) in ranges {
 5973                        linked_edits
 5974                            .entry(buffer.clone())
 5975                            .or_default()
 5976                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 5977                    }
 5978                }
 5979            }
 5980        }
 5981
 5982        let common_prefix_len = old_text
 5983            .chars()
 5984            .zip(new_text.chars())
 5985            .take_while(|(a, b)| a == b)
 5986            .map(|(a, _)| a.len_utf8())
 5987            .sum::<usize>();
 5988
 5989        cx.emit(EditorEvent::InputHandled {
 5990            utf16_range_to_replace: None,
 5991            text: new_text[common_prefix_len..].into(),
 5992        });
 5993
 5994        self.transact(window, cx, |editor, window, cx| {
 5995            if let Some(mut snippet) = snippet {
 5996                snippet.text = new_text.to_string();
 5997                editor
 5998                    .insert_snippet(&ranges, snippet, window, cx)
 5999                    .log_err();
 6000            } else {
 6001                editor.buffer.update(cx, |multi_buffer, cx| {
 6002                    let auto_indent = match completion.insert_text_mode {
 6003                        Some(InsertTextMode::AS_IS) => None,
 6004                        _ => editor.autoindent_mode.clone(),
 6005                    };
 6006                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 6007                    multi_buffer.edit(edits, auto_indent, cx);
 6008                });
 6009            }
 6010            for (buffer, edits) in linked_edits {
 6011                buffer.update(cx, |buffer, cx| {
 6012                    let snapshot = buffer.snapshot();
 6013                    let edits = edits
 6014                        .into_iter()
 6015                        .map(|(range, text)| {
 6016                            use text::ToPoint as TP;
 6017                            let end_point = TP::to_point(&range.end, &snapshot);
 6018                            let start_point = TP::to_point(&range.start, &snapshot);
 6019                            (start_point..end_point, text)
 6020                        })
 6021                        .sorted_by_key(|(range, _)| range.start);
 6022                    buffer.edit(edits, None, cx);
 6023                })
 6024            }
 6025
 6026            editor.refresh_edit_prediction(true, false, window, cx);
 6027        });
 6028        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors_arc(), &snapshot);
 6029
 6030        let show_new_completions_on_confirm = completion
 6031            .confirm
 6032            .as_ref()
 6033            .is_some_and(|confirm| confirm(intent, window, cx));
 6034        if show_new_completions_on_confirm {
 6035            self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 6036        }
 6037
 6038        let provider = self.completion_provider.as_ref()?;
 6039        drop(completion);
 6040        let apply_edits = provider.apply_additional_edits_for_completion(
 6041            buffer_handle,
 6042            completions_menu.completions.clone(),
 6043            candidate_id,
 6044            true,
 6045            cx,
 6046        );
 6047
 6048        let editor_settings = EditorSettings::get_global(cx);
 6049        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 6050            // After the code completion is finished, users often want to know what signatures are needed.
 6051            // so we should automatically call signature_help
 6052            self.show_signature_help(&ShowSignatureHelp, window, cx);
 6053        }
 6054
 6055        Some(cx.foreground_executor().spawn(async move {
 6056            apply_edits.await?;
 6057            Ok(())
 6058        }))
 6059    }
 6060
 6061    pub fn toggle_code_actions(
 6062        &mut self,
 6063        action: &ToggleCodeActions,
 6064        window: &mut Window,
 6065        cx: &mut Context<Self>,
 6066    ) {
 6067        let quick_launch = action.quick_launch;
 6068        let mut context_menu = self.context_menu.borrow_mut();
 6069        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 6070            if code_actions.deployed_from == action.deployed_from {
 6071                // Toggle if we're selecting the same one
 6072                *context_menu = None;
 6073                cx.notify();
 6074                return;
 6075            } else {
 6076                // Otherwise, clear it and start a new one
 6077                *context_menu = None;
 6078                cx.notify();
 6079            }
 6080        }
 6081        drop(context_menu);
 6082        let snapshot = self.snapshot(window, cx);
 6083        let deployed_from = action.deployed_from.clone();
 6084        let action = action.clone();
 6085        self.completion_tasks.clear();
 6086        self.discard_edit_prediction(false, cx);
 6087
 6088        let multibuffer_point = match &action.deployed_from {
 6089            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 6090                DisplayPoint::new(*row, 0).to_point(&snapshot)
 6091            }
 6092            _ => self
 6093                .selections
 6094                .newest::<Point>(&snapshot.display_snapshot)
 6095                .head(),
 6096        };
 6097        let Some((buffer, buffer_row)) = snapshot
 6098            .buffer_snapshot()
 6099            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 6100            .and_then(|(buffer_snapshot, range)| {
 6101                self.buffer()
 6102                    .read(cx)
 6103                    .buffer(buffer_snapshot.remote_id())
 6104                    .map(|buffer| (buffer, range.start.row))
 6105            })
 6106        else {
 6107            return;
 6108        };
 6109        let buffer_id = buffer.read(cx).remote_id();
 6110        let tasks = self
 6111            .tasks
 6112            .get(&(buffer_id, buffer_row))
 6113            .map(|t| Arc::new(t.to_owned()));
 6114
 6115        if !self.focus_handle.is_focused(window) {
 6116            return;
 6117        }
 6118        let project = self.project.clone();
 6119
 6120        let code_actions_task = match deployed_from {
 6121            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 6122            _ => self.code_actions(buffer_row, window, cx),
 6123        };
 6124
 6125        let runnable_task = match deployed_from {
 6126            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 6127            _ => {
 6128                let mut task_context_task = Task::ready(None);
 6129                if let Some(tasks) = &tasks
 6130                    && let Some(project) = project
 6131                {
 6132                    task_context_task =
 6133                        Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx);
 6134                }
 6135
 6136                cx.spawn_in(window, {
 6137                    let buffer = buffer.clone();
 6138                    async move |editor, cx| {
 6139                        let task_context = task_context_task.await;
 6140
 6141                        let resolved_tasks =
 6142                            tasks
 6143                                .zip(task_context.clone())
 6144                                .map(|(tasks, task_context)| ResolvedTasks {
 6145                                    templates: tasks.resolve(&task_context).collect(),
 6146                                    position: snapshot.buffer_snapshot().anchor_before(Point::new(
 6147                                        multibuffer_point.row,
 6148                                        tasks.column,
 6149                                    )),
 6150                                });
 6151                        let debug_scenarios = editor
 6152                            .update(cx, |editor, cx| {
 6153                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 6154                            })?
 6155                            .await;
 6156                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 6157                    }
 6158                })
 6159            }
 6160        };
 6161
 6162        cx.spawn_in(window, async move |editor, cx| {
 6163            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 6164            let code_actions = code_actions_task.await;
 6165            let spawn_straight_away = quick_launch
 6166                && resolved_tasks
 6167                    .as_ref()
 6168                    .is_some_and(|tasks| tasks.templates.len() == 1)
 6169                && code_actions
 6170                    .as_ref()
 6171                    .is_none_or(|actions| actions.is_empty())
 6172                && debug_scenarios.is_empty();
 6173
 6174            editor.update_in(cx, |editor, window, cx| {
 6175                crate::hover_popover::hide_hover(editor, cx);
 6176                let actions = CodeActionContents::new(
 6177                    resolved_tasks,
 6178                    code_actions,
 6179                    debug_scenarios,
 6180                    task_context.unwrap_or_default(),
 6181                );
 6182
 6183                // Don't show the menu if there are no actions available
 6184                if actions.is_empty() {
 6185                    cx.notify();
 6186                    return Task::ready(Ok(()));
 6187                }
 6188
 6189                *editor.context_menu.borrow_mut() =
 6190                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 6191                        buffer,
 6192                        actions,
 6193                        selected_item: Default::default(),
 6194                        scroll_handle: UniformListScrollHandle::default(),
 6195                        deployed_from,
 6196                    }));
 6197                cx.notify();
 6198                if spawn_straight_away
 6199                    && let Some(task) = editor.confirm_code_action(
 6200                        &ConfirmCodeAction { item_ix: Some(0) },
 6201                        window,
 6202                        cx,
 6203                    )
 6204                {
 6205                    return task;
 6206                }
 6207
 6208                Task::ready(Ok(()))
 6209            })
 6210        })
 6211        .detach_and_log_err(cx);
 6212    }
 6213
 6214    fn debug_scenarios(
 6215        &mut self,
 6216        resolved_tasks: &Option<ResolvedTasks>,
 6217        buffer: &Entity<Buffer>,
 6218        cx: &mut App,
 6219    ) -> Task<Vec<task::DebugScenario>> {
 6220        maybe!({
 6221            let project = self.project()?;
 6222            let dap_store = project.read(cx).dap_store();
 6223            let mut scenarios = vec![];
 6224            let resolved_tasks = resolved_tasks.as_ref()?;
 6225            let buffer = buffer.read(cx);
 6226            let language = buffer.language()?;
 6227            let file = buffer.file();
 6228            let debug_adapter = language_settings(language.name().into(), file, cx)
 6229                .debuggers
 6230                .first()
 6231                .map(SharedString::from)
 6232                .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 6233
 6234            dap_store.update(cx, |dap_store, cx| {
 6235                for (_, task) in &resolved_tasks.templates {
 6236                    let maybe_scenario = dap_store.debug_scenario_for_build_task(
 6237                        task.original_task().clone(),
 6238                        debug_adapter.clone().into(),
 6239                        task.display_label().to_owned().into(),
 6240                        cx,
 6241                    );
 6242                    scenarios.push(maybe_scenario);
 6243                }
 6244            });
 6245            Some(cx.background_spawn(async move {
 6246                futures::future::join_all(scenarios)
 6247                    .await
 6248                    .into_iter()
 6249                    .flatten()
 6250                    .collect::<Vec<_>>()
 6251            }))
 6252        })
 6253        .unwrap_or_else(|| Task::ready(vec![]))
 6254    }
 6255
 6256    fn code_actions(
 6257        &mut self,
 6258        buffer_row: u32,
 6259        window: &mut Window,
 6260        cx: &mut Context<Self>,
 6261    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 6262        let mut task = self.code_actions_task.take();
 6263        cx.spawn_in(window, async move |editor, cx| {
 6264            while let Some(prev_task) = task {
 6265                prev_task.await.log_err();
 6266                task = editor
 6267                    .update(cx, |this, _| this.code_actions_task.take())
 6268                    .ok()?;
 6269            }
 6270
 6271            editor
 6272                .update(cx, |editor, cx| {
 6273                    editor
 6274                        .available_code_actions
 6275                        .clone()
 6276                        .and_then(|(location, code_actions)| {
 6277                            let snapshot = location.buffer.read(cx).snapshot();
 6278                            let point_range = location.range.to_point(&snapshot);
 6279                            let point_range = point_range.start.row..=point_range.end.row;
 6280                            if point_range.contains(&buffer_row) {
 6281                                Some(code_actions)
 6282                            } else {
 6283                                None
 6284                            }
 6285                        })
 6286                })
 6287                .ok()
 6288                .flatten()
 6289        })
 6290    }
 6291
 6292    pub fn confirm_code_action(
 6293        &mut self,
 6294        action: &ConfirmCodeAction,
 6295        window: &mut Window,
 6296        cx: &mut Context<Self>,
 6297    ) -> Option<Task<Result<()>>> {
 6298        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6299
 6300        let actions_menu =
 6301            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 6302                menu
 6303            } else {
 6304                return None;
 6305            };
 6306
 6307        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 6308        let action = actions_menu.actions.get(action_ix)?;
 6309        let title = action.label();
 6310        let buffer = actions_menu.buffer;
 6311        let workspace = self.workspace()?;
 6312
 6313        match action {
 6314            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 6315                workspace.update(cx, |workspace, cx| {
 6316                    workspace.schedule_resolved_task(
 6317                        task_source_kind,
 6318                        resolved_task,
 6319                        false,
 6320                        window,
 6321                        cx,
 6322                    );
 6323
 6324                    Some(Task::ready(Ok(())))
 6325                })
 6326            }
 6327            CodeActionsItem::CodeAction {
 6328                excerpt_id,
 6329                action,
 6330                provider,
 6331            } => {
 6332                let apply_code_action =
 6333                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 6334                let workspace = workspace.downgrade();
 6335                Some(cx.spawn_in(window, async move |editor, cx| {
 6336                    let project_transaction = apply_code_action.await?;
 6337                    Self::open_project_transaction(
 6338                        &editor,
 6339                        workspace,
 6340                        project_transaction,
 6341                        title,
 6342                        cx,
 6343                    )
 6344                    .await
 6345                }))
 6346            }
 6347            CodeActionsItem::DebugScenario(scenario) => {
 6348                let context = actions_menu.actions.context;
 6349
 6350                workspace.update(cx, |workspace, cx| {
 6351                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 6352                    workspace.start_debug_session(
 6353                        scenario,
 6354                        context,
 6355                        Some(buffer),
 6356                        None,
 6357                        window,
 6358                        cx,
 6359                    );
 6360                });
 6361                Some(Task::ready(Ok(())))
 6362            }
 6363        }
 6364    }
 6365
 6366    pub async fn open_project_transaction(
 6367        editor: &WeakEntity<Editor>,
 6368        workspace: WeakEntity<Workspace>,
 6369        transaction: ProjectTransaction,
 6370        title: String,
 6371        cx: &mut AsyncWindowContext,
 6372    ) -> Result<()> {
 6373        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 6374        cx.update(|_, cx| {
 6375            entries.sort_unstable_by_key(|(buffer, _)| {
 6376                buffer.read(cx).file().map(|f| f.path().clone())
 6377            });
 6378        })?;
 6379        if entries.is_empty() {
 6380            return Ok(());
 6381        }
 6382
 6383        // If the project transaction's edits are all contained within this editor, then
 6384        // avoid opening a new editor to display them.
 6385
 6386        if let [(buffer, transaction)] = &*entries {
 6387            let excerpt = editor.update(cx, |editor, cx| {
 6388                editor
 6389                    .buffer()
 6390                    .read(cx)
 6391                    .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6392            })?;
 6393            if let Some((_, excerpted_buffer, excerpt_range)) = excerpt
 6394                && excerpted_buffer == *buffer
 6395            {
 6396                let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6397                    let excerpt_range = excerpt_range.to_offset(buffer);
 6398                    buffer
 6399                        .edited_ranges_for_transaction::<usize>(transaction)
 6400                        .all(|range| {
 6401                            excerpt_range.start <= range.start && excerpt_range.end >= range.end
 6402                        })
 6403                })?;
 6404
 6405                if all_edits_within_excerpt {
 6406                    return Ok(());
 6407                }
 6408            }
 6409        }
 6410
 6411        let mut ranges_to_highlight = Vec::new();
 6412        let excerpt_buffer = cx.new(|cx| {
 6413            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6414            for (buffer_handle, transaction) in &entries {
 6415                let edited_ranges = buffer_handle
 6416                    .read(cx)
 6417                    .edited_ranges_for_transaction::<Point>(transaction)
 6418                    .collect::<Vec<_>>();
 6419                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6420                    PathKey::for_buffer(buffer_handle, cx),
 6421                    buffer_handle.clone(),
 6422                    edited_ranges,
 6423                    multibuffer_context_lines(cx),
 6424                    cx,
 6425                );
 6426
 6427                ranges_to_highlight.extend(ranges);
 6428            }
 6429            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6430            multibuffer
 6431        })?;
 6432
 6433        workspace.update_in(cx, |workspace, window, cx| {
 6434            let project = workspace.project().clone();
 6435            let editor =
 6436                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6437            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6438            editor.update(cx, |editor, cx| {
 6439                editor.highlight_background::<Self>(
 6440                    &ranges_to_highlight,
 6441                    |theme| theme.colors().editor_highlighted_line_background,
 6442                    cx,
 6443                );
 6444            });
 6445        })?;
 6446
 6447        Ok(())
 6448    }
 6449
 6450    pub fn clear_code_action_providers(&mut self) {
 6451        self.code_action_providers.clear();
 6452        self.available_code_actions.take();
 6453    }
 6454
 6455    pub fn add_code_action_provider(
 6456        &mut self,
 6457        provider: Rc<dyn CodeActionProvider>,
 6458        window: &mut Window,
 6459        cx: &mut Context<Self>,
 6460    ) {
 6461        if self
 6462            .code_action_providers
 6463            .iter()
 6464            .any(|existing_provider| existing_provider.id() == provider.id())
 6465        {
 6466            return;
 6467        }
 6468
 6469        self.code_action_providers.push(provider);
 6470        self.refresh_code_actions(window, cx);
 6471    }
 6472
 6473    pub fn remove_code_action_provider(
 6474        &mut self,
 6475        id: Arc<str>,
 6476        window: &mut Window,
 6477        cx: &mut Context<Self>,
 6478    ) {
 6479        self.code_action_providers
 6480            .retain(|provider| provider.id() != id);
 6481        self.refresh_code_actions(window, cx);
 6482    }
 6483
 6484    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6485        !self.code_action_providers.is_empty()
 6486            && EditorSettings::get_global(cx).toolbar.code_actions
 6487    }
 6488
 6489    pub fn has_available_code_actions(&self) -> bool {
 6490        self.available_code_actions
 6491            .as_ref()
 6492            .is_some_and(|(_, actions)| !actions.is_empty())
 6493    }
 6494
 6495    fn render_inline_code_actions(
 6496        &self,
 6497        icon_size: ui::IconSize,
 6498        display_row: DisplayRow,
 6499        is_active: bool,
 6500        cx: &mut Context<Self>,
 6501    ) -> AnyElement {
 6502        let show_tooltip = !self.context_menu_visible();
 6503        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6504            .icon_size(icon_size)
 6505            .shape(ui::IconButtonShape::Square)
 6506            .icon_color(ui::Color::Hidden)
 6507            .toggle_state(is_active)
 6508            .when(show_tooltip, |this| {
 6509                this.tooltip({
 6510                    let focus_handle = self.focus_handle.clone();
 6511                    move |_window, cx| {
 6512                        Tooltip::for_action_in(
 6513                            "Toggle Code Actions",
 6514                            &ToggleCodeActions {
 6515                                deployed_from: None,
 6516                                quick_launch: false,
 6517                            },
 6518                            &focus_handle,
 6519                            cx,
 6520                        )
 6521                    }
 6522                })
 6523            })
 6524            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6525                window.focus(&editor.focus_handle(cx));
 6526                editor.toggle_code_actions(
 6527                    &crate::actions::ToggleCodeActions {
 6528                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6529                            display_row,
 6530                        )),
 6531                        quick_launch: false,
 6532                    },
 6533                    window,
 6534                    cx,
 6535                );
 6536            }))
 6537            .into_any_element()
 6538    }
 6539
 6540    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6541        &self.context_menu
 6542    }
 6543
 6544    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6545        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6546            cx.background_executor()
 6547                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6548                .await;
 6549
 6550            let (start_buffer, start, _, end, newest_selection) = this
 6551                .update(cx, |this, cx| {
 6552                    let newest_selection = this.selections.newest_anchor().clone();
 6553                    if newest_selection.head().diff_base_anchor.is_some() {
 6554                        return None;
 6555                    }
 6556                    let display_snapshot = this.display_snapshot(cx);
 6557                    let newest_selection_adjusted =
 6558                        this.selections.newest_adjusted(&display_snapshot);
 6559                    let buffer = this.buffer.read(cx);
 6560
 6561                    let (start_buffer, start) =
 6562                        buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6563                    let (end_buffer, end) =
 6564                        buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6565
 6566                    Some((start_buffer, start, end_buffer, end, newest_selection))
 6567                })?
 6568                .filter(|(start_buffer, _, end_buffer, _, _)| start_buffer == end_buffer)
 6569                .context(
 6570                    "Expected selection to lie in a single buffer when refreshing code actions",
 6571                )?;
 6572            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6573                let providers = this.code_action_providers.clone();
 6574                let tasks = this
 6575                    .code_action_providers
 6576                    .iter()
 6577                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6578                    .collect::<Vec<_>>();
 6579                (providers, tasks)
 6580            })?;
 6581
 6582            let mut actions = Vec::new();
 6583            for (provider, provider_actions) in
 6584                providers.into_iter().zip(future::join_all(tasks).await)
 6585            {
 6586                if let Some(provider_actions) = provider_actions.log_err() {
 6587                    actions.extend(provider_actions.into_iter().map(|action| {
 6588                        AvailableCodeAction {
 6589                            excerpt_id: newest_selection.start.excerpt_id,
 6590                            action,
 6591                            provider: provider.clone(),
 6592                        }
 6593                    }));
 6594                }
 6595            }
 6596
 6597            this.update(cx, |this, cx| {
 6598                this.available_code_actions = if actions.is_empty() {
 6599                    None
 6600                } else {
 6601                    Some((
 6602                        Location {
 6603                            buffer: start_buffer,
 6604                            range: start..end,
 6605                        },
 6606                        actions.into(),
 6607                    ))
 6608                };
 6609                cx.notify();
 6610            })
 6611        }));
 6612    }
 6613
 6614    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6615        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6616            self.show_git_blame_inline = false;
 6617
 6618            self.show_git_blame_inline_delay_task =
 6619                Some(cx.spawn_in(window, async move |this, cx| {
 6620                    cx.background_executor().timer(delay).await;
 6621
 6622                    this.update(cx, |this, cx| {
 6623                        this.show_git_blame_inline = true;
 6624                        cx.notify();
 6625                    })
 6626                    .log_err();
 6627                }));
 6628        }
 6629    }
 6630
 6631    pub fn blame_hover(&mut self, _: &BlameHover, window: &mut Window, cx: &mut Context<Self>) {
 6632        let snapshot = self.snapshot(window, cx);
 6633        let cursor = self
 6634            .selections
 6635            .newest::<Point>(&snapshot.display_snapshot)
 6636            .head();
 6637        let Some((buffer, point, _)) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)
 6638        else {
 6639            return;
 6640        };
 6641
 6642        let Some(blame) = self.blame.as_ref() else {
 6643            return;
 6644        };
 6645
 6646        let row_info = RowInfo {
 6647            buffer_id: Some(buffer.remote_id()),
 6648            buffer_row: Some(point.row),
 6649            ..Default::default()
 6650        };
 6651        let Some((buffer, blame_entry)) = blame
 6652            .update(cx, |blame, cx| blame.blame_for_rows(&[row_info], cx).next())
 6653            .flatten()
 6654        else {
 6655            return;
 6656        };
 6657
 6658        let anchor = self.selections.newest_anchor().head();
 6659        let position = self.to_pixel_point(anchor, &snapshot, window);
 6660        if let (Some(position), Some(last_bounds)) = (position, self.last_bounds) {
 6661            self.show_blame_popover(
 6662                buffer,
 6663                &blame_entry,
 6664                position + last_bounds.origin,
 6665                true,
 6666                cx,
 6667            );
 6668        };
 6669    }
 6670
 6671    fn show_blame_popover(
 6672        &mut self,
 6673        buffer: BufferId,
 6674        blame_entry: &BlameEntry,
 6675        position: gpui::Point<Pixels>,
 6676        ignore_timeout: bool,
 6677        cx: &mut Context<Self>,
 6678    ) {
 6679        if let Some(state) = &mut self.inline_blame_popover {
 6680            state.hide_task.take();
 6681        } else {
 6682            let blame_popover_delay = EditorSettings::get_global(cx).hover_popover_delay.0;
 6683            let blame_entry = blame_entry.clone();
 6684            let show_task = cx.spawn(async move |editor, cx| {
 6685                if !ignore_timeout {
 6686                    cx.background_executor()
 6687                        .timer(std::time::Duration::from_millis(blame_popover_delay))
 6688                        .await;
 6689                }
 6690                editor
 6691                    .update(cx, |editor, cx| {
 6692                        editor.inline_blame_popover_show_task.take();
 6693                        let Some(blame) = editor.blame.as_ref() else {
 6694                            return;
 6695                        };
 6696                        let blame = blame.read(cx);
 6697                        let details = blame.details_for_entry(buffer, &blame_entry);
 6698                        let markdown = cx.new(|cx| {
 6699                            Markdown::new(
 6700                                details
 6701                                    .as_ref()
 6702                                    .map(|message| message.message.clone())
 6703                                    .unwrap_or_default(),
 6704                                None,
 6705                                None,
 6706                                cx,
 6707                            )
 6708                        });
 6709                        editor.inline_blame_popover = Some(InlineBlamePopover {
 6710                            position,
 6711                            hide_task: None,
 6712                            popover_bounds: None,
 6713                            popover_state: InlineBlamePopoverState {
 6714                                scroll_handle: ScrollHandle::new(),
 6715                                commit_message: details,
 6716                                markdown,
 6717                            },
 6718                            keyboard_grace: ignore_timeout,
 6719                        });
 6720                        cx.notify();
 6721                    })
 6722                    .ok();
 6723            });
 6724            self.inline_blame_popover_show_task = Some(show_task);
 6725        }
 6726    }
 6727
 6728    fn hide_blame_popover(&mut self, ignore_timeout: bool, cx: &mut Context<Self>) -> bool {
 6729        self.inline_blame_popover_show_task.take();
 6730        if let Some(state) = &mut self.inline_blame_popover {
 6731            let hide_task = cx.spawn(async move |editor, cx| {
 6732                if !ignore_timeout {
 6733                    cx.background_executor()
 6734                        .timer(std::time::Duration::from_millis(100))
 6735                        .await;
 6736                }
 6737                editor
 6738                    .update(cx, |editor, cx| {
 6739                        editor.inline_blame_popover.take();
 6740                        cx.notify();
 6741                    })
 6742                    .ok();
 6743            });
 6744            state.hide_task = Some(hide_task);
 6745            true
 6746        } else {
 6747            false
 6748        }
 6749    }
 6750
 6751    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 6752        if self.pending_rename.is_some() {
 6753            return None;
 6754        }
 6755
 6756        let provider = self.semantics_provider.clone()?;
 6757        let buffer = self.buffer.read(cx);
 6758        let newest_selection = self.selections.newest_anchor().clone();
 6759        let cursor_position = newest_selection.head();
 6760        let (cursor_buffer, cursor_buffer_position) =
 6761            buffer.text_anchor_for_position(cursor_position, cx)?;
 6762        let (tail_buffer, tail_buffer_position) =
 6763            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 6764        if cursor_buffer != tail_buffer {
 6765            return None;
 6766        }
 6767
 6768        let snapshot = cursor_buffer.read(cx).snapshot();
 6769        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position, None);
 6770        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position, None);
 6771        if start_word_range != end_word_range {
 6772            self.document_highlights_task.take();
 6773            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6774            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6775            return None;
 6776        }
 6777
 6778        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce.0;
 6779        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6780            cx.background_executor()
 6781                .timer(Duration::from_millis(debounce))
 6782                .await;
 6783
 6784            let highlights = if let Some(highlights) = cx
 6785                .update(|cx| {
 6786                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 6787                })
 6788                .ok()
 6789                .flatten()
 6790            {
 6791                highlights.await.log_err()
 6792            } else {
 6793                None
 6794            };
 6795
 6796            if let Some(highlights) = highlights {
 6797                this.update(cx, |this, cx| {
 6798                    if this.pending_rename.is_some() {
 6799                        return;
 6800                    }
 6801
 6802                    let buffer = this.buffer.read(cx);
 6803                    if buffer
 6804                        .text_anchor_for_position(cursor_position, cx)
 6805                        .is_none_or(|(buffer, _)| buffer != cursor_buffer)
 6806                    {
 6807                        return;
 6808                    }
 6809
 6810                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 6811                    let mut write_ranges = Vec::new();
 6812                    let mut read_ranges = Vec::new();
 6813                    for highlight in highlights {
 6814                        let buffer_id = cursor_buffer.read(cx).remote_id();
 6815                        for (excerpt_id, excerpt_range) in buffer.excerpts_for_buffer(buffer_id, cx)
 6816                        {
 6817                            let start = highlight
 6818                                .range
 6819                                .start
 6820                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 6821                            let end = highlight
 6822                                .range
 6823                                .end
 6824                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6825                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6826                                continue;
 6827                            }
 6828
 6829                            let range =
 6830                                Anchor::range_in_buffer(excerpt_id, buffer_id, *start..*end);
 6831                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 6832                                write_ranges.push(range);
 6833                            } else {
 6834                                read_ranges.push(range);
 6835                            }
 6836                        }
 6837                    }
 6838
 6839                    this.highlight_background::<DocumentHighlightRead>(
 6840                        &read_ranges,
 6841                        |theme| theme.colors().editor_document_highlight_read_background,
 6842                        cx,
 6843                    );
 6844                    this.highlight_background::<DocumentHighlightWrite>(
 6845                        &write_ranges,
 6846                        |theme| theme.colors().editor_document_highlight_write_background,
 6847                        cx,
 6848                    );
 6849                    cx.notify();
 6850                })
 6851                .log_err();
 6852            }
 6853        }));
 6854        None
 6855    }
 6856
 6857    fn prepare_highlight_query_from_selection(
 6858        &mut self,
 6859        window: &Window,
 6860        cx: &mut Context<Editor>,
 6861    ) -> Option<(String, Range<Anchor>)> {
 6862        if matches!(self.mode, EditorMode::SingleLine) {
 6863            return None;
 6864        }
 6865        if !EditorSettings::get_global(cx).selection_highlight {
 6866            return None;
 6867        }
 6868        if self.selections.count() != 1 || self.selections.line_mode() {
 6869            return None;
 6870        }
 6871        let snapshot = self.snapshot(window, cx);
 6872        let selection = self.selections.newest::<Point>(&snapshot);
 6873        // If the selection spans multiple rows OR it is empty
 6874        if selection.start.row != selection.end.row
 6875            || selection.start.column == selection.end.column
 6876        {
 6877            return None;
 6878        }
 6879        let selection_anchor_range = selection.range().to_anchors(snapshot.buffer_snapshot());
 6880        let query = snapshot
 6881            .buffer_snapshot()
 6882            .text_for_range(selection_anchor_range.clone())
 6883            .collect::<String>();
 6884        if query.trim().is_empty() {
 6885            return None;
 6886        }
 6887        Some((query, selection_anchor_range))
 6888    }
 6889
 6890    fn update_selection_occurrence_highlights(
 6891        &mut self,
 6892        query_text: String,
 6893        query_range: Range<Anchor>,
 6894        multi_buffer_range_to_query: Range<Point>,
 6895        use_debounce: bool,
 6896        window: &mut Window,
 6897        cx: &mut Context<Editor>,
 6898    ) -> Task<()> {
 6899        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6900        cx.spawn_in(window, async move |editor, cx| {
 6901            if use_debounce {
 6902                cx.background_executor()
 6903                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 6904                    .await;
 6905            }
 6906            let match_task = cx.background_spawn(async move {
 6907                let buffer_ranges = multi_buffer_snapshot
 6908                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 6909                    .into_iter()
 6910                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 6911                let mut match_ranges = Vec::new();
 6912                let Ok(regex) = project::search::SearchQuery::text(
 6913                    query_text.clone(),
 6914                    false,
 6915                    false,
 6916                    false,
 6917                    Default::default(),
 6918                    Default::default(),
 6919                    false,
 6920                    None,
 6921                ) else {
 6922                    return Vec::default();
 6923                };
 6924                let query_range = query_range.to_anchors(&multi_buffer_snapshot);
 6925                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 6926                    match_ranges.extend(
 6927                        regex
 6928                            .search(buffer_snapshot, Some(search_range.clone()))
 6929                            .await
 6930                            .into_iter()
 6931                            .filter_map(|match_range| {
 6932                                let match_start = buffer_snapshot
 6933                                    .anchor_after(search_range.start + match_range.start);
 6934                                let match_end = buffer_snapshot
 6935                                    .anchor_before(search_range.start + match_range.end);
 6936                                let match_anchor_range = Anchor::range_in_buffer(
 6937                                    excerpt_id,
 6938                                    buffer_snapshot.remote_id(),
 6939                                    match_start..match_end,
 6940                                );
 6941                                (match_anchor_range != query_range).then_some(match_anchor_range)
 6942                            }),
 6943                    );
 6944                }
 6945                match_ranges
 6946            });
 6947            let match_ranges = match_task.await;
 6948            editor
 6949                .update_in(cx, |editor, _, cx| {
 6950                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 6951                    if !match_ranges.is_empty() {
 6952                        editor.highlight_background::<SelectedTextHighlight>(
 6953                            &match_ranges,
 6954                            |theme| theme.colors().editor_document_highlight_bracket_background,
 6955                            cx,
 6956                        )
 6957                    }
 6958                })
 6959                .log_err();
 6960        })
 6961    }
 6962
 6963    fn refresh_single_line_folds(&mut self, window: &mut Window, cx: &mut Context<Editor>) {
 6964        struct NewlineFold;
 6965        let type_id = std::any::TypeId::of::<NewlineFold>();
 6966        if !self.mode.is_single_line() {
 6967            return;
 6968        }
 6969        let snapshot = self.snapshot(window, cx);
 6970        if snapshot.buffer_snapshot().max_point().row == 0 {
 6971            return;
 6972        }
 6973        let task = cx.background_spawn(async move {
 6974            let new_newlines = snapshot
 6975                .buffer_chars_at(0)
 6976                .filter_map(|(c, i)| {
 6977                    if c == '\n' {
 6978                        Some(
 6979                            snapshot.buffer_snapshot().anchor_after(i)
 6980                                ..snapshot.buffer_snapshot().anchor_before(i + 1),
 6981                        )
 6982                    } else {
 6983                        None
 6984                    }
 6985                })
 6986                .collect::<Vec<_>>();
 6987            let existing_newlines = snapshot
 6988                .folds_in_range(0..snapshot.buffer_snapshot().len())
 6989                .filter_map(|fold| {
 6990                    if fold.placeholder.type_tag == Some(type_id) {
 6991                        Some(fold.range.start..fold.range.end)
 6992                    } else {
 6993                        None
 6994                    }
 6995                })
 6996                .collect::<Vec<_>>();
 6997
 6998            (new_newlines, existing_newlines)
 6999        });
 7000        self.folding_newlines = cx.spawn(async move |this, cx| {
 7001            let (new_newlines, existing_newlines) = task.await;
 7002            if new_newlines == existing_newlines {
 7003                return;
 7004            }
 7005            let placeholder = FoldPlaceholder {
 7006                render: Arc::new(move |_, _, cx| {
 7007                    div()
 7008                        .bg(cx.theme().status().hint_background)
 7009                        .border_b_1()
 7010                        .size_full()
 7011                        .font(ThemeSettings::get_global(cx).buffer_font.clone())
 7012                        .border_color(cx.theme().status().hint)
 7013                        .child("\\n")
 7014                        .into_any()
 7015                }),
 7016                constrain_width: false,
 7017                merge_adjacent: false,
 7018                type_tag: Some(type_id),
 7019            };
 7020            let creases = new_newlines
 7021                .into_iter()
 7022                .map(|range| Crease::simple(range, placeholder.clone()))
 7023                .collect();
 7024            this.update(cx, |this, cx| {
 7025                this.display_map.update(cx, |display_map, cx| {
 7026                    display_map.remove_folds_with_type(existing_newlines, type_id, cx);
 7027                    display_map.fold(creases, cx);
 7028                });
 7029            })
 7030            .ok();
 7031        });
 7032    }
 7033
 7034    fn refresh_selected_text_highlights(
 7035        &mut self,
 7036        on_buffer_edit: bool,
 7037        window: &mut Window,
 7038        cx: &mut Context<Editor>,
 7039    ) {
 7040        let Some((query_text, query_range)) =
 7041            self.prepare_highlight_query_from_selection(window, cx)
 7042        else {
 7043            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 7044            self.quick_selection_highlight_task.take();
 7045            self.debounced_selection_highlight_task.take();
 7046            return;
 7047        };
 7048        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 7049        if on_buffer_edit
 7050            || self
 7051                .quick_selection_highlight_task
 7052                .as_ref()
 7053                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7054        {
 7055            let multi_buffer_visible_start = self
 7056                .scroll_manager
 7057                .anchor()
 7058                .anchor
 7059                .to_point(&multi_buffer_snapshot);
 7060            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 7061                multi_buffer_visible_start
 7062                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 7063                Bias::Left,
 7064            );
 7065            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 7066            self.quick_selection_highlight_task = Some((
 7067                query_range.clone(),
 7068                self.update_selection_occurrence_highlights(
 7069                    query_text.clone(),
 7070                    query_range.clone(),
 7071                    multi_buffer_visible_range,
 7072                    false,
 7073                    window,
 7074                    cx,
 7075                ),
 7076            ));
 7077        }
 7078        if on_buffer_edit
 7079            || self
 7080                .debounced_selection_highlight_task
 7081                .as_ref()
 7082                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7083        {
 7084            let multi_buffer_start = multi_buffer_snapshot
 7085                .anchor_before(0)
 7086                .to_point(&multi_buffer_snapshot);
 7087            let multi_buffer_end = multi_buffer_snapshot
 7088                .anchor_after(multi_buffer_snapshot.len())
 7089                .to_point(&multi_buffer_snapshot);
 7090            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 7091            self.debounced_selection_highlight_task = Some((
 7092                query_range.clone(),
 7093                self.update_selection_occurrence_highlights(
 7094                    query_text,
 7095                    query_range,
 7096                    multi_buffer_full_range,
 7097                    true,
 7098                    window,
 7099                    cx,
 7100                ),
 7101            ));
 7102        }
 7103    }
 7104
 7105    pub fn refresh_edit_prediction(
 7106        &mut self,
 7107        debounce: bool,
 7108        user_requested: bool,
 7109        window: &mut Window,
 7110        cx: &mut Context<Self>,
 7111    ) -> Option<()> {
 7112        if DisableAiSettings::get_global(cx).disable_ai {
 7113            return None;
 7114        }
 7115
 7116        let provider = self.edit_prediction_provider()?;
 7117        let cursor = self.selections.newest_anchor().head();
 7118        let (buffer, cursor_buffer_position) =
 7119            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7120
 7121        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 7122            self.discard_edit_prediction(false, cx);
 7123            return None;
 7124        }
 7125
 7126        self.update_visible_edit_prediction(window, cx);
 7127
 7128        if !user_requested
 7129            && (!self.should_show_edit_predictions()
 7130                || !self.is_focused(window)
 7131                || buffer.read(cx).is_empty())
 7132        {
 7133            self.discard_edit_prediction(false, cx);
 7134            return None;
 7135        }
 7136
 7137        provider.refresh(buffer, cursor_buffer_position, debounce, cx);
 7138        Some(())
 7139    }
 7140
 7141    fn show_edit_predictions_in_menu(&self) -> bool {
 7142        match self.edit_prediction_settings {
 7143            EditPredictionSettings::Disabled => false,
 7144            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 7145        }
 7146    }
 7147
 7148    pub fn edit_predictions_enabled(&self) -> bool {
 7149        match self.edit_prediction_settings {
 7150            EditPredictionSettings::Disabled => false,
 7151            EditPredictionSettings::Enabled { .. } => true,
 7152        }
 7153    }
 7154
 7155    fn edit_prediction_requires_modifier(&self) -> bool {
 7156        match self.edit_prediction_settings {
 7157            EditPredictionSettings::Disabled => false,
 7158            EditPredictionSettings::Enabled {
 7159                preview_requires_modifier,
 7160                ..
 7161            } => preview_requires_modifier,
 7162        }
 7163    }
 7164
 7165    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 7166        if self.edit_prediction_provider.is_none() || DisableAiSettings::get_global(cx).disable_ai {
 7167            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7168            self.discard_edit_prediction(false, cx);
 7169        } else {
 7170            let selection = self.selections.newest_anchor();
 7171            let cursor = selection.head();
 7172
 7173            if let Some((buffer, cursor_buffer_position)) =
 7174                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7175            {
 7176                self.edit_prediction_settings =
 7177                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7178            }
 7179        }
 7180    }
 7181
 7182    fn edit_prediction_settings_at_position(
 7183        &self,
 7184        buffer: &Entity<Buffer>,
 7185        buffer_position: language::Anchor,
 7186        cx: &App,
 7187    ) -> EditPredictionSettings {
 7188        if !self.mode.is_full()
 7189            || !self.show_edit_predictions_override.unwrap_or(true)
 7190            || self.edit_predictions_disabled_in_scope(buffer, buffer_position, cx)
 7191        {
 7192            return EditPredictionSettings::Disabled;
 7193        }
 7194
 7195        let buffer = buffer.read(cx);
 7196
 7197        let file = buffer.file();
 7198
 7199        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 7200            return EditPredictionSettings::Disabled;
 7201        };
 7202
 7203        let by_provider = matches!(
 7204            self.menu_edit_predictions_policy,
 7205            MenuEditPredictionsPolicy::ByProvider
 7206        );
 7207
 7208        let show_in_menu = by_provider
 7209            && self
 7210                .edit_prediction_provider
 7211                .as_ref()
 7212                .is_some_and(|provider| provider.provider.show_completions_in_menu());
 7213
 7214        let preview_requires_modifier =
 7215            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 7216
 7217        EditPredictionSettings::Enabled {
 7218            show_in_menu,
 7219            preview_requires_modifier,
 7220        }
 7221    }
 7222
 7223    fn should_show_edit_predictions(&self) -> bool {
 7224        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 7225    }
 7226
 7227    pub fn edit_prediction_preview_is_active(&self) -> bool {
 7228        matches!(
 7229            self.edit_prediction_preview,
 7230            EditPredictionPreview::Active { .. }
 7231        )
 7232    }
 7233
 7234    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 7235        let cursor = self.selections.newest_anchor().head();
 7236        if let Some((buffer, cursor_position)) =
 7237            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7238        {
 7239            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 7240        } else {
 7241            false
 7242        }
 7243    }
 7244
 7245    pub fn supports_minimap(&self, cx: &App) -> bool {
 7246        !self.minimap_visibility.disabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton
 7247    }
 7248
 7249    fn edit_predictions_enabled_in_buffer(
 7250        &self,
 7251        buffer: &Entity<Buffer>,
 7252        buffer_position: language::Anchor,
 7253        cx: &App,
 7254    ) -> bool {
 7255        maybe!({
 7256            if self.read_only(cx) {
 7257                return Some(false);
 7258            }
 7259            let provider = self.edit_prediction_provider()?;
 7260            if !provider.is_enabled(buffer, buffer_position, cx) {
 7261                return Some(false);
 7262            }
 7263            let buffer = buffer.read(cx);
 7264            let Some(file) = buffer.file() else {
 7265                return Some(true);
 7266            };
 7267            let settings = all_language_settings(Some(file), cx);
 7268            Some(settings.edit_predictions_enabled_for_file(file, cx))
 7269        })
 7270        .unwrap_or(false)
 7271    }
 7272
 7273    fn cycle_edit_prediction(
 7274        &mut self,
 7275        direction: Direction,
 7276        window: &mut Window,
 7277        cx: &mut Context<Self>,
 7278    ) -> Option<()> {
 7279        let provider = self.edit_prediction_provider()?;
 7280        let cursor = self.selections.newest_anchor().head();
 7281        let (buffer, cursor_buffer_position) =
 7282            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7283        if self.edit_predictions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 7284            return None;
 7285        }
 7286
 7287        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 7288        self.update_visible_edit_prediction(window, cx);
 7289
 7290        Some(())
 7291    }
 7292
 7293    pub fn show_edit_prediction(
 7294        &mut self,
 7295        _: &ShowEditPrediction,
 7296        window: &mut Window,
 7297        cx: &mut Context<Self>,
 7298    ) {
 7299        if !self.has_active_edit_prediction() {
 7300            self.refresh_edit_prediction(false, true, window, cx);
 7301            return;
 7302        }
 7303
 7304        self.update_visible_edit_prediction(window, cx);
 7305    }
 7306
 7307    pub fn display_cursor_names(
 7308        &mut self,
 7309        _: &DisplayCursorNames,
 7310        window: &mut Window,
 7311        cx: &mut Context<Self>,
 7312    ) {
 7313        self.show_cursor_names(window, cx);
 7314    }
 7315
 7316    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7317        self.show_cursor_names = true;
 7318        cx.notify();
 7319        cx.spawn_in(window, async move |this, cx| {
 7320            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 7321            this.update(cx, |this, cx| {
 7322                this.show_cursor_names = false;
 7323                cx.notify()
 7324            })
 7325            .ok()
 7326        })
 7327        .detach();
 7328    }
 7329
 7330    pub fn next_edit_prediction(
 7331        &mut self,
 7332        _: &NextEditPrediction,
 7333        window: &mut Window,
 7334        cx: &mut Context<Self>,
 7335    ) {
 7336        if self.has_active_edit_prediction() {
 7337            self.cycle_edit_prediction(Direction::Next, window, cx);
 7338        } else {
 7339            let is_copilot_disabled = self
 7340                .refresh_edit_prediction(false, true, window, cx)
 7341                .is_none();
 7342            if is_copilot_disabled {
 7343                cx.propagate();
 7344            }
 7345        }
 7346    }
 7347
 7348    pub fn previous_edit_prediction(
 7349        &mut self,
 7350        _: &PreviousEditPrediction,
 7351        window: &mut Window,
 7352        cx: &mut Context<Self>,
 7353    ) {
 7354        if self.has_active_edit_prediction() {
 7355            self.cycle_edit_prediction(Direction::Prev, window, cx);
 7356        } else {
 7357            let is_copilot_disabled = self
 7358                .refresh_edit_prediction(false, true, window, cx)
 7359                .is_none();
 7360            if is_copilot_disabled {
 7361                cx.propagate();
 7362            }
 7363        }
 7364    }
 7365
 7366    pub fn accept_edit_prediction(
 7367        &mut self,
 7368        _: &AcceptEditPrediction,
 7369        window: &mut Window,
 7370        cx: &mut Context<Self>,
 7371    ) {
 7372        if self.show_edit_predictions_in_menu() {
 7373            self.hide_context_menu(window, cx);
 7374        }
 7375
 7376        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7377            return;
 7378        };
 7379
 7380        match &active_edit_prediction.completion {
 7381            EditPrediction::MoveWithin { target, .. } => {
 7382                let target = *target;
 7383
 7384                if let Some(position_map) = &self.last_position_map {
 7385                    if position_map
 7386                        .visible_row_range
 7387                        .contains(&target.to_display_point(&position_map.snapshot).row())
 7388                        || !self.edit_prediction_requires_modifier()
 7389                    {
 7390                        self.unfold_ranges(&[target..target], true, false, cx);
 7391                        // Note that this is also done in vim's handler of the Tab action.
 7392                        self.change_selections(
 7393                            SelectionEffects::scroll(Autoscroll::newest()),
 7394                            window,
 7395                            cx,
 7396                            |selections| {
 7397                                selections.select_anchor_ranges([target..target]);
 7398                            },
 7399                        );
 7400                        self.clear_row_highlights::<EditPredictionPreview>();
 7401
 7402                        self.edit_prediction_preview
 7403                            .set_previous_scroll_position(None);
 7404                    } else {
 7405                        self.edit_prediction_preview
 7406                            .set_previous_scroll_position(Some(
 7407                                position_map.snapshot.scroll_anchor,
 7408                            ));
 7409
 7410                        self.highlight_rows::<EditPredictionPreview>(
 7411                            target..target,
 7412                            cx.theme().colors().editor_highlighted_line_background,
 7413                            RowHighlightOptions {
 7414                                autoscroll: true,
 7415                                ..Default::default()
 7416                            },
 7417                            cx,
 7418                        );
 7419                        self.request_autoscroll(Autoscroll::fit(), cx);
 7420                    }
 7421                }
 7422            }
 7423            EditPrediction::MoveOutside { snapshot, target } => {
 7424                if let Some(workspace) = self.workspace() {
 7425                    Self::open_editor_at_anchor(snapshot, *target, &workspace, window, cx)
 7426                        .detach_and_log_err(cx);
 7427                }
 7428            }
 7429            EditPrediction::Edit { edits, .. } => {
 7430                self.report_edit_prediction_event(
 7431                    active_edit_prediction.completion_id.clone(),
 7432                    true,
 7433                    cx,
 7434                );
 7435
 7436                if let Some(provider) = self.edit_prediction_provider() {
 7437                    provider.accept(cx);
 7438                }
 7439
 7440                // Store the transaction ID and selections before applying the edit
 7441                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 7442
 7443                let snapshot = self.buffer.read(cx).snapshot(cx);
 7444                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 7445
 7446                self.buffer.update(cx, |buffer, cx| {
 7447                    buffer.edit(edits.iter().cloned(), None, cx)
 7448                });
 7449
 7450                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 7451                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 7452                });
 7453
 7454                let selections = self.selections.disjoint_anchors_arc();
 7455                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 7456                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 7457                    if has_new_transaction {
 7458                        self.selection_history
 7459                            .insert_transaction(transaction_id_now, selections);
 7460                    }
 7461                }
 7462
 7463                self.update_visible_edit_prediction(window, cx);
 7464                if self.active_edit_prediction.is_none() {
 7465                    self.refresh_edit_prediction(true, true, window, cx);
 7466                }
 7467
 7468                cx.notify();
 7469            }
 7470        }
 7471
 7472        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 7473    }
 7474
 7475    pub fn accept_partial_edit_prediction(
 7476        &mut self,
 7477        _: &AcceptPartialEditPrediction,
 7478        window: &mut Window,
 7479        cx: &mut Context<Self>,
 7480    ) {
 7481        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7482            return;
 7483        };
 7484        if self.selections.count() != 1 {
 7485            return;
 7486        }
 7487
 7488        match &active_edit_prediction.completion {
 7489            EditPrediction::MoveWithin { target, .. } => {
 7490                let target = *target;
 7491                self.change_selections(
 7492                    SelectionEffects::scroll(Autoscroll::newest()),
 7493                    window,
 7494                    cx,
 7495                    |selections| {
 7496                        selections.select_anchor_ranges([target..target]);
 7497                    },
 7498                );
 7499            }
 7500            EditPrediction::MoveOutside { snapshot, target } => {
 7501                if let Some(workspace) = self.workspace() {
 7502                    Self::open_editor_at_anchor(snapshot, *target, &workspace, window, cx)
 7503                        .detach_and_log_err(cx);
 7504                }
 7505            }
 7506            EditPrediction::Edit { edits, .. } => {
 7507                self.report_edit_prediction_event(
 7508                    active_edit_prediction.completion_id.clone(),
 7509                    true,
 7510                    cx,
 7511                );
 7512
 7513                // Find an insertion that starts at the cursor position.
 7514                let snapshot = self.buffer.read(cx).snapshot(cx);
 7515                let cursor_offset = self
 7516                    .selections
 7517                    .newest::<usize>(&self.display_snapshot(cx))
 7518                    .head();
 7519                let insertion = edits.iter().find_map(|(range, text)| {
 7520                    let range = range.to_offset(&snapshot);
 7521                    if range.is_empty() && range.start == cursor_offset {
 7522                        Some(text)
 7523                    } else {
 7524                        None
 7525                    }
 7526                });
 7527
 7528                if let Some(text) = insertion {
 7529                    let mut partial_completion = text
 7530                        .chars()
 7531                        .by_ref()
 7532                        .take_while(|c| c.is_alphabetic())
 7533                        .collect::<String>();
 7534                    if partial_completion.is_empty() {
 7535                        partial_completion = text
 7536                            .chars()
 7537                            .by_ref()
 7538                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7539                            .collect::<String>();
 7540                    }
 7541
 7542                    cx.emit(EditorEvent::InputHandled {
 7543                        utf16_range_to_replace: None,
 7544                        text: partial_completion.clone().into(),
 7545                    });
 7546
 7547                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 7548
 7549                    self.refresh_edit_prediction(true, true, window, cx);
 7550                    cx.notify();
 7551                } else {
 7552                    self.accept_edit_prediction(&Default::default(), window, cx);
 7553                }
 7554            }
 7555        }
 7556    }
 7557
 7558    fn discard_edit_prediction(
 7559        &mut self,
 7560        should_report_edit_prediction_event: bool,
 7561        cx: &mut Context<Self>,
 7562    ) -> bool {
 7563        if should_report_edit_prediction_event {
 7564            let completion_id = self
 7565                .active_edit_prediction
 7566                .as_ref()
 7567                .and_then(|active_completion| active_completion.completion_id.clone());
 7568
 7569            self.report_edit_prediction_event(completion_id, false, cx);
 7570        }
 7571
 7572        if let Some(provider) = self.edit_prediction_provider() {
 7573            provider.discard(cx);
 7574        }
 7575
 7576        self.take_active_edit_prediction(cx)
 7577    }
 7578
 7579    fn report_edit_prediction_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7580        let Some(provider) = self.edit_prediction_provider() else {
 7581            return;
 7582        };
 7583
 7584        let Some((_, buffer, _)) = self
 7585            .buffer
 7586            .read(cx)
 7587            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7588        else {
 7589            return;
 7590        };
 7591
 7592        let extension = buffer
 7593            .read(cx)
 7594            .file()
 7595            .and_then(|file| Some(file.path().extension()?.to_string()));
 7596
 7597        let event_type = match accepted {
 7598            true => "Edit Prediction Accepted",
 7599            false => "Edit Prediction Discarded",
 7600        };
 7601        telemetry::event!(
 7602            event_type,
 7603            provider = provider.name(),
 7604            prediction_id = id,
 7605            suggestion_accepted = accepted,
 7606            file_extension = extension,
 7607        );
 7608    }
 7609
 7610    fn open_editor_at_anchor(
 7611        snapshot: &language::BufferSnapshot,
 7612        target: language::Anchor,
 7613        workspace: &Entity<Workspace>,
 7614        window: &mut Window,
 7615        cx: &mut App,
 7616    ) -> Task<Result<()>> {
 7617        workspace.update(cx, |workspace, cx| {
 7618            let path = snapshot.file().map(|file| file.full_path(cx));
 7619            let Some(path) =
 7620                path.and_then(|path| workspace.project().read(cx).find_project_path(path, cx))
 7621            else {
 7622                return Task::ready(Err(anyhow::anyhow!("Project path not found")));
 7623            };
 7624            let target = text::ToPoint::to_point(&target, snapshot);
 7625            let item = workspace.open_path(path, None, true, window, cx);
 7626            window.spawn(cx, async move |cx| {
 7627                let Some(editor) = item.await?.downcast::<Editor>() else {
 7628                    return Ok(());
 7629                };
 7630                editor
 7631                    .update_in(cx, |editor, window, cx| {
 7632                        editor.go_to_singleton_buffer_point(target, window, cx);
 7633                    })
 7634                    .ok();
 7635                anyhow::Ok(())
 7636            })
 7637        })
 7638    }
 7639
 7640    pub fn has_active_edit_prediction(&self) -> bool {
 7641        self.active_edit_prediction.is_some()
 7642    }
 7643
 7644    fn take_active_edit_prediction(&mut self, cx: &mut Context<Self>) -> bool {
 7645        let Some(active_edit_prediction) = self.active_edit_prediction.take() else {
 7646            return false;
 7647        };
 7648
 7649        self.splice_inlays(&active_edit_prediction.inlay_ids, Default::default(), cx);
 7650        self.clear_highlights::<EditPredictionHighlight>(cx);
 7651        self.stale_edit_prediction_in_menu = Some(active_edit_prediction);
 7652        true
 7653    }
 7654
 7655    /// Returns true when we're displaying the edit prediction popover below the cursor
 7656    /// like we are not previewing and the LSP autocomplete menu is visible
 7657    /// or we are in `when_holding_modifier` mode.
 7658    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7659        if self.edit_prediction_preview_is_active()
 7660            || !self.show_edit_predictions_in_menu()
 7661            || !self.edit_predictions_enabled()
 7662        {
 7663            return false;
 7664        }
 7665
 7666        if self.has_visible_completions_menu() {
 7667            return true;
 7668        }
 7669
 7670        has_completion && self.edit_prediction_requires_modifier()
 7671    }
 7672
 7673    fn handle_modifiers_changed(
 7674        &mut self,
 7675        modifiers: Modifiers,
 7676        position_map: &PositionMap,
 7677        window: &mut Window,
 7678        cx: &mut Context<Self>,
 7679    ) {
 7680        // Ensure that the edit prediction preview is updated, even when not
 7681        // enabled, if there's an active edit prediction preview.
 7682        if self.show_edit_predictions_in_menu()
 7683            || matches!(
 7684                self.edit_prediction_preview,
 7685                EditPredictionPreview::Active { .. }
 7686            )
 7687        {
 7688            self.update_edit_prediction_preview(&modifiers, window, cx);
 7689        }
 7690
 7691        self.update_selection_mode(&modifiers, position_map, window, cx);
 7692
 7693        let mouse_position = window.mouse_position();
 7694        if !position_map.text_hitbox.is_hovered(window) {
 7695            return;
 7696        }
 7697
 7698        self.update_hovered_link(
 7699            position_map.point_for_position(mouse_position),
 7700            &position_map.snapshot,
 7701            modifiers,
 7702            window,
 7703            cx,
 7704        )
 7705    }
 7706
 7707    fn is_cmd_or_ctrl_pressed(modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7708        match EditorSettings::get_global(cx).multi_cursor_modifier {
 7709            MultiCursorModifier::Alt => modifiers.secondary(),
 7710            MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 7711        }
 7712    }
 7713
 7714    fn is_alt_pressed(modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7715        match EditorSettings::get_global(cx).multi_cursor_modifier {
 7716            MultiCursorModifier::Alt => modifiers.alt,
 7717            MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 7718        }
 7719    }
 7720
 7721    fn columnar_selection_mode(
 7722        modifiers: &Modifiers,
 7723        cx: &mut Context<Self>,
 7724    ) -> Option<ColumnarMode> {
 7725        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 7726            if Self::is_cmd_or_ctrl_pressed(modifiers, cx) {
 7727                Some(ColumnarMode::FromMouse)
 7728            } else if Self::is_alt_pressed(modifiers, cx) {
 7729                Some(ColumnarMode::FromSelection)
 7730            } else {
 7731                None
 7732            }
 7733        } else {
 7734            None
 7735        }
 7736    }
 7737
 7738    fn update_selection_mode(
 7739        &mut self,
 7740        modifiers: &Modifiers,
 7741        position_map: &PositionMap,
 7742        window: &mut Window,
 7743        cx: &mut Context<Self>,
 7744    ) {
 7745        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 7746            return;
 7747        };
 7748        if self.selections.pending_anchor().is_none() {
 7749            return;
 7750        }
 7751
 7752        let mouse_position = window.mouse_position();
 7753        let point_for_position = position_map.point_for_position(mouse_position);
 7754        let position = point_for_position.previous_valid;
 7755
 7756        self.select(
 7757            SelectPhase::BeginColumnar {
 7758                position,
 7759                reset: false,
 7760                mode,
 7761                goal_column: point_for_position.exact_unclipped.column(),
 7762            },
 7763            window,
 7764            cx,
 7765        );
 7766    }
 7767
 7768    fn update_edit_prediction_preview(
 7769        &mut self,
 7770        modifiers: &Modifiers,
 7771        window: &mut Window,
 7772        cx: &mut Context<Self>,
 7773    ) {
 7774        let mut modifiers_held = false;
 7775        if let Some(accept_keystroke) = self
 7776            .accept_edit_prediction_keybind(false, window, cx)
 7777            .keystroke()
 7778        {
 7779            modifiers_held = modifiers_held
 7780                || (accept_keystroke.modifiers() == modifiers
 7781                    && accept_keystroke.modifiers().modified());
 7782        };
 7783        if let Some(accept_partial_keystroke) = self
 7784            .accept_edit_prediction_keybind(true, window, cx)
 7785            .keystroke()
 7786        {
 7787            modifiers_held = modifiers_held
 7788                || (accept_partial_keystroke.modifiers() == modifiers
 7789                    && accept_partial_keystroke.modifiers().modified());
 7790        }
 7791
 7792        if modifiers_held {
 7793            if matches!(
 7794                self.edit_prediction_preview,
 7795                EditPredictionPreview::Inactive { .. }
 7796            ) {
 7797                self.edit_prediction_preview = EditPredictionPreview::Active {
 7798                    previous_scroll_position: None,
 7799                    since: Instant::now(),
 7800                };
 7801
 7802                self.update_visible_edit_prediction(window, cx);
 7803                cx.notify();
 7804            }
 7805        } else if let EditPredictionPreview::Active {
 7806            previous_scroll_position,
 7807            since,
 7808        } = self.edit_prediction_preview
 7809        {
 7810            if let (Some(previous_scroll_position), Some(position_map)) =
 7811                (previous_scroll_position, self.last_position_map.as_ref())
 7812            {
 7813                self.set_scroll_position(
 7814                    previous_scroll_position
 7815                        .scroll_position(&position_map.snapshot.display_snapshot),
 7816                    window,
 7817                    cx,
 7818                );
 7819            }
 7820
 7821            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 7822                released_too_fast: since.elapsed() < Duration::from_millis(200),
 7823            };
 7824            self.clear_row_highlights::<EditPredictionPreview>();
 7825            self.update_visible_edit_prediction(window, cx);
 7826            cx.notify();
 7827        }
 7828    }
 7829
 7830    fn update_visible_edit_prediction(
 7831        &mut self,
 7832        _window: &mut Window,
 7833        cx: &mut Context<Self>,
 7834    ) -> Option<()> {
 7835        if DisableAiSettings::get_global(cx).disable_ai {
 7836            return None;
 7837        }
 7838
 7839        if self.ime_transaction.is_some() {
 7840            self.discard_edit_prediction(false, cx);
 7841            return None;
 7842        }
 7843
 7844        let selection = self.selections.newest_anchor();
 7845        let cursor = selection.head();
 7846        let multibuffer = self.buffer.read(cx).snapshot(cx);
 7847        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 7848        let excerpt_id = cursor.excerpt_id;
 7849
 7850        let show_in_menu = self.show_edit_predictions_in_menu();
 7851        let completions_menu_has_precedence = !show_in_menu
 7852            && (self.context_menu.borrow().is_some()
 7853                || (!self.completion_tasks.is_empty() && !self.has_active_edit_prediction()));
 7854
 7855        if completions_menu_has_precedence
 7856            || !offset_selection.is_empty()
 7857            || self
 7858                .active_edit_prediction
 7859                .as_ref()
 7860                .is_some_and(|completion| {
 7861                    let Some(invalidation_range) = completion.invalidation_range.as_ref() else {
 7862                        return false;
 7863                    };
 7864                    let invalidation_range = invalidation_range.to_offset(&multibuffer);
 7865                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 7866                    !invalidation_range.contains(&offset_selection.head())
 7867                })
 7868        {
 7869            self.discard_edit_prediction(false, cx);
 7870            return None;
 7871        }
 7872
 7873        self.take_active_edit_prediction(cx);
 7874        let Some(provider) = self.edit_prediction_provider() else {
 7875            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7876            return None;
 7877        };
 7878
 7879        let (buffer, cursor_buffer_position) =
 7880            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7881
 7882        self.edit_prediction_settings =
 7883            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7884
 7885        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 7886
 7887        if self.edit_prediction_indent_conflict {
 7888            let cursor_point = cursor.to_point(&multibuffer);
 7889
 7890            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 7891
 7892            if let Some((_, indent)) = indents.iter().next()
 7893                && indent.len == cursor_point.column
 7894            {
 7895                self.edit_prediction_indent_conflict = false;
 7896            }
 7897        }
 7898
 7899        let edit_prediction = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 7900
 7901        let (completion_id, edits, edit_preview) = match edit_prediction {
 7902            edit_prediction::EditPrediction::Local {
 7903                id,
 7904                edits,
 7905                edit_preview,
 7906            } => (id, edits, edit_preview),
 7907            edit_prediction::EditPrediction::Jump {
 7908                id,
 7909                snapshot,
 7910                target,
 7911            } => {
 7912                self.stale_edit_prediction_in_menu = None;
 7913                self.active_edit_prediction = Some(EditPredictionState {
 7914                    inlay_ids: vec![],
 7915                    completion: EditPrediction::MoveOutside { snapshot, target },
 7916                    completion_id: id,
 7917                    invalidation_range: None,
 7918                });
 7919                cx.notify();
 7920                return Some(());
 7921            }
 7922        };
 7923
 7924        let edits = edits
 7925            .into_iter()
 7926            .flat_map(|(range, new_text)| {
 7927                Some((
 7928                    multibuffer.anchor_range_in_excerpt(excerpt_id, range)?,
 7929                    new_text,
 7930                ))
 7931            })
 7932            .collect::<Vec<_>>();
 7933        if edits.is_empty() {
 7934            return None;
 7935        }
 7936
 7937        let first_edit_start = edits.first().unwrap().0.start;
 7938        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 7939        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 7940
 7941        let last_edit_end = edits.last().unwrap().0.end;
 7942        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 7943        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 7944
 7945        let cursor_row = cursor.to_point(&multibuffer).row;
 7946
 7947        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 7948
 7949        let mut inlay_ids = Vec::new();
 7950        let invalidation_row_range;
 7951        let move_invalidation_row_range = if cursor_row < edit_start_row {
 7952            Some(cursor_row..edit_end_row)
 7953        } else if cursor_row > edit_end_row {
 7954            Some(edit_start_row..cursor_row)
 7955        } else {
 7956            None
 7957        };
 7958        let supports_jump = self
 7959            .edit_prediction_provider
 7960            .as_ref()
 7961            .map(|provider| provider.provider.supports_jump_to_edit())
 7962            .unwrap_or(true);
 7963
 7964        let is_move = supports_jump
 7965            && (move_invalidation_row_range.is_some() || self.edit_predictions_hidden_for_vim_mode);
 7966        let completion = if is_move {
 7967            invalidation_row_range =
 7968                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 7969            let target = first_edit_start;
 7970            EditPrediction::MoveWithin { target, snapshot }
 7971        } else {
 7972            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 7973                && !self.edit_predictions_hidden_for_vim_mode;
 7974
 7975            if show_completions_in_buffer {
 7976                if edits
 7977                    .iter()
 7978                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 7979                {
 7980                    let mut inlays = Vec::new();
 7981                    for (range, new_text) in &edits {
 7982                        let inlay = Inlay::edit_prediction(
 7983                            post_inc(&mut self.next_inlay_id),
 7984                            range.start,
 7985                            new_text.as_ref(),
 7986                        );
 7987                        inlay_ids.push(inlay.id);
 7988                        inlays.push(inlay);
 7989                    }
 7990
 7991                    self.splice_inlays(&[], inlays, cx);
 7992                } else {
 7993                    let background_color = cx.theme().status().deleted_background;
 7994                    self.highlight_text::<EditPredictionHighlight>(
 7995                        edits.iter().map(|(range, _)| range.clone()).collect(),
 7996                        HighlightStyle {
 7997                            background_color: Some(background_color),
 7998                            ..Default::default()
 7999                        },
 8000                        cx,
 8001                    );
 8002                }
 8003            }
 8004
 8005            invalidation_row_range = edit_start_row..edit_end_row;
 8006
 8007            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 8008                if provider.show_tab_accept_marker() {
 8009                    EditDisplayMode::TabAccept
 8010                } else {
 8011                    EditDisplayMode::Inline
 8012                }
 8013            } else {
 8014                EditDisplayMode::DiffPopover
 8015            };
 8016
 8017            EditPrediction::Edit {
 8018                edits,
 8019                edit_preview,
 8020                display_mode,
 8021                snapshot,
 8022            }
 8023        };
 8024
 8025        let invalidation_range = multibuffer
 8026            .anchor_before(Point::new(invalidation_row_range.start, 0))
 8027            ..multibuffer.anchor_after(Point::new(
 8028                invalidation_row_range.end,
 8029                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 8030            ));
 8031
 8032        self.stale_edit_prediction_in_menu = None;
 8033        self.active_edit_prediction = Some(EditPredictionState {
 8034            inlay_ids,
 8035            completion,
 8036            completion_id,
 8037            invalidation_range: Some(invalidation_range),
 8038        });
 8039
 8040        cx.notify();
 8041
 8042        Some(())
 8043    }
 8044
 8045    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn EditPredictionProviderHandle>> {
 8046        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 8047    }
 8048
 8049    fn clear_tasks(&mut self) {
 8050        self.tasks.clear()
 8051    }
 8052
 8053    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 8054        if self.tasks.insert(key, value).is_some() {
 8055            // This case should hopefully be rare, but just in case...
 8056            log::error!(
 8057                "multiple different run targets found on a single line, only the last target will be rendered"
 8058            )
 8059        }
 8060    }
 8061
 8062    /// Get all display points of breakpoints that will be rendered within editor
 8063    ///
 8064    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 8065    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 8066    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 8067    fn active_breakpoints(
 8068        &self,
 8069        range: Range<DisplayRow>,
 8070        window: &mut Window,
 8071        cx: &mut Context<Self>,
 8072    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 8073        let mut breakpoint_display_points = HashMap::default();
 8074
 8075        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 8076            return breakpoint_display_points;
 8077        };
 8078
 8079        let snapshot = self.snapshot(window, cx);
 8080
 8081        let multi_buffer_snapshot = snapshot.buffer_snapshot();
 8082        let Some(project) = self.project() else {
 8083            return breakpoint_display_points;
 8084        };
 8085
 8086        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 8087            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 8088
 8089        for (buffer_snapshot, range, excerpt_id) in
 8090            multi_buffer_snapshot.range_to_buffer_ranges(range)
 8091        {
 8092            let Some(buffer) = project
 8093                .read(cx)
 8094                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 8095            else {
 8096                continue;
 8097            };
 8098            let breakpoints = breakpoint_store.read(cx).breakpoints(
 8099                &buffer,
 8100                Some(
 8101                    buffer_snapshot.anchor_before(range.start)
 8102                        ..buffer_snapshot.anchor_after(range.end),
 8103                ),
 8104                buffer_snapshot,
 8105                cx,
 8106            );
 8107            for (breakpoint, state) in breakpoints {
 8108                let multi_buffer_anchor =
 8109                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 8110                let position = multi_buffer_anchor
 8111                    .to_point(&multi_buffer_snapshot)
 8112                    .to_display_point(&snapshot);
 8113
 8114                breakpoint_display_points.insert(
 8115                    position.row(),
 8116                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 8117                );
 8118            }
 8119        }
 8120
 8121        breakpoint_display_points
 8122    }
 8123
 8124    fn breakpoint_context_menu(
 8125        &self,
 8126        anchor: Anchor,
 8127        window: &mut Window,
 8128        cx: &mut Context<Self>,
 8129    ) -> Entity<ui::ContextMenu> {
 8130        let weak_editor = cx.weak_entity();
 8131        let focus_handle = self.focus_handle(cx);
 8132
 8133        let row = self
 8134            .buffer
 8135            .read(cx)
 8136            .snapshot(cx)
 8137            .summary_for_anchor::<Point>(&anchor)
 8138            .row;
 8139
 8140        let breakpoint = self
 8141            .breakpoint_at_row(row, window, cx)
 8142            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 8143
 8144        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 8145            "Edit Log Breakpoint"
 8146        } else {
 8147            "Set Log Breakpoint"
 8148        };
 8149
 8150        let condition_breakpoint_msg = if breakpoint
 8151            .as_ref()
 8152            .is_some_and(|bp| bp.1.condition.is_some())
 8153        {
 8154            "Edit Condition Breakpoint"
 8155        } else {
 8156            "Set Condition Breakpoint"
 8157        };
 8158
 8159        let hit_condition_breakpoint_msg = if breakpoint
 8160            .as_ref()
 8161            .is_some_and(|bp| bp.1.hit_condition.is_some())
 8162        {
 8163            "Edit Hit Condition Breakpoint"
 8164        } else {
 8165            "Set Hit Condition Breakpoint"
 8166        };
 8167
 8168        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 8169            "Unset Breakpoint"
 8170        } else {
 8171            "Set Breakpoint"
 8172        };
 8173
 8174        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 8175
 8176        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 8177            BreakpointState::Enabled => Some("Disable"),
 8178            BreakpointState::Disabled => Some("Enable"),
 8179        });
 8180
 8181        let (anchor, breakpoint) =
 8182            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 8183
 8184        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 8185            menu.on_blur_subscription(Subscription::new(|| {}))
 8186                .context(focus_handle)
 8187                .when(run_to_cursor, |this| {
 8188                    let weak_editor = weak_editor.clone();
 8189                    this.entry("Run to cursor", None, move |window, cx| {
 8190                        weak_editor
 8191                            .update(cx, |editor, cx| {
 8192                                editor.change_selections(
 8193                                    SelectionEffects::no_scroll(),
 8194                                    window,
 8195                                    cx,
 8196                                    |s| s.select_ranges([Point::new(row, 0)..Point::new(row, 0)]),
 8197                                );
 8198                            })
 8199                            .ok();
 8200
 8201                        window.dispatch_action(Box::new(RunToCursor), cx);
 8202                    })
 8203                    .separator()
 8204                })
 8205                .when_some(toggle_state_msg, |this, msg| {
 8206                    this.entry(msg, None, {
 8207                        let weak_editor = weak_editor.clone();
 8208                        let breakpoint = breakpoint.clone();
 8209                        move |_window, cx| {
 8210                            weak_editor
 8211                                .update(cx, |this, cx| {
 8212                                    this.edit_breakpoint_at_anchor(
 8213                                        anchor,
 8214                                        breakpoint.as_ref().clone(),
 8215                                        BreakpointEditAction::InvertState,
 8216                                        cx,
 8217                                    );
 8218                                })
 8219                                .log_err();
 8220                        }
 8221                    })
 8222                })
 8223                .entry(set_breakpoint_msg, None, {
 8224                    let weak_editor = weak_editor.clone();
 8225                    let breakpoint = breakpoint.clone();
 8226                    move |_window, cx| {
 8227                        weak_editor
 8228                            .update(cx, |this, cx| {
 8229                                this.edit_breakpoint_at_anchor(
 8230                                    anchor,
 8231                                    breakpoint.as_ref().clone(),
 8232                                    BreakpointEditAction::Toggle,
 8233                                    cx,
 8234                                );
 8235                            })
 8236                            .log_err();
 8237                    }
 8238                })
 8239                .entry(log_breakpoint_msg, None, {
 8240                    let breakpoint = breakpoint.clone();
 8241                    let weak_editor = weak_editor.clone();
 8242                    move |window, cx| {
 8243                        weak_editor
 8244                            .update(cx, |this, cx| {
 8245                                this.add_edit_breakpoint_block(
 8246                                    anchor,
 8247                                    breakpoint.as_ref(),
 8248                                    BreakpointPromptEditAction::Log,
 8249                                    window,
 8250                                    cx,
 8251                                );
 8252                            })
 8253                            .log_err();
 8254                    }
 8255                })
 8256                .entry(condition_breakpoint_msg, None, {
 8257                    let breakpoint = breakpoint.clone();
 8258                    let weak_editor = weak_editor.clone();
 8259                    move |window, cx| {
 8260                        weak_editor
 8261                            .update(cx, |this, cx| {
 8262                                this.add_edit_breakpoint_block(
 8263                                    anchor,
 8264                                    breakpoint.as_ref(),
 8265                                    BreakpointPromptEditAction::Condition,
 8266                                    window,
 8267                                    cx,
 8268                                );
 8269                            })
 8270                            .log_err();
 8271                    }
 8272                })
 8273                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 8274                    weak_editor
 8275                        .update(cx, |this, cx| {
 8276                            this.add_edit_breakpoint_block(
 8277                                anchor,
 8278                                breakpoint.as_ref(),
 8279                                BreakpointPromptEditAction::HitCondition,
 8280                                window,
 8281                                cx,
 8282                            );
 8283                        })
 8284                        .log_err();
 8285                })
 8286        })
 8287    }
 8288
 8289    fn render_breakpoint(
 8290        &self,
 8291        position: Anchor,
 8292        row: DisplayRow,
 8293        breakpoint: &Breakpoint,
 8294        state: Option<BreakpointSessionState>,
 8295        cx: &mut Context<Self>,
 8296    ) -> IconButton {
 8297        let is_rejected = state.is_some_and(|s| !s.verified);
 8298        // Is it a breakpoint that shows up when hovering over gutter?
 8299        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 8300            (false, false),
 8301            |PhantomBreakpointIndicator {
 8302                 is_active,
 8303                 display_row,
 8304                 collides_with_existing_breakpoint,
 8305             }| {
 8306                (
 8307                    is_active && display_row == row,
 8308                    collides_with_existing_breakpoint,
 8309                )
 8310            },
 8311        );
 8312
 8313        let (color, icon) = {
 8314            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 8315                (false, false) => ui::IconName::DebugBreakpoint,
 8316                (true, false) => ui::IconName::DebugLogBreakpoint,
 8317                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 8318                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 8319            };
 8320
 8321            let color = if is_phantom {
 8322                Color::Hint
 8323            } else if is_rejected {
 8324                Color::Disabled
 8325            } else {
 8326                Color::Debugger
 8327            };
 8328
 8329            (color, icon)
 8330        };
 8331
 8332        let breakpoint = Arc::from(breakpoint.clone());
 8333
 8334        let alt_as_text = gpui::Keystroke {
 8335            modifiers: Modifiers::secondary_key(),
 8336            ..Default::default()
 8337        };
 8338        let primary_action_text = if breakpoint.is_disabled() {
 8339            "Enable breakpoint"
 8340        } else if is_phantom && !collides_with_existing {
 8341            "Set breakpoint"
 8342        } else {
 8343            "Unset breakpoint"
 8344        };
 8345        let focus_handle = self.focus_handle.clone();
 8346
 8347        let meta = if is_rejected {
 8348            SharedString::from("No executable code is associated with this line.")
 8349        } else if collides_with_existing && !breakpoint.is_disabled() {
 8350            SharedString::from(format!(
 8351                "{alt_as_text}-click to disable,\nright-click for more options."
 8352            ))
 8353        } else {
 8354            SharedString::from("Right-click for more options.")
 8355        };
 8356        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 8357            .icon_size(IconSize::XSmall)
 8358            .size(ui::ButtonSize::None)
 8359            .when(is_rejected, |this| {
 8360                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 8361            })
 8362            .icon_color(color)
 8363            .style(ButtonStyle::Transparent)
 8364            .on_click(cx.listener({
 8365                move |editor, event: &ClickEvent, window, cx| {
 8366                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 8367                        BreakpointEditAction::InvertState
 8368                    } else {
 8369                        BreakpointEditAction::Toggle
 8370                    };
 8371
 8372                    window.focus(&editor.focus_handle(cx));
 8373                    editor.edit_breakpoint_at_anchor(
 8374                        position,
 8375                        breakpoint.as_ref().clone(),
 8376                        edit_action,
 8377                        cx,
 8378                    );
 8379                }
 8380            }))
 8381            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8382                editor.set_breakpoint_context_menu(
 8383                    row,
 8384                    Some(position),
 8385                    event.position(),
 8386                    window,
 8387                    cx,
 8388                );
 8389            }))
 8390            .tooltip(move |_window, cx| {
 8391                Tooltip::with_meta_in(
 8392                    primary_action_text,
 8393                    Some(&ToggleBreakpoint),
 8394                    meta.clone(),
 8395                    &focus_handle,
 8396                    cx,
 8397                )
 8398            })
 8399    }
 8400
 8401    fn build_tasks_context(
 8402        project: &Entity<Project>,
 8403        buffer: &Entity<Buffer>,
 8404        buffer_row: u32,
 8405        tasks: &Arc<RunnableTasks>,
 8406        cx: &mut Context<Self>,
 8407    ) -> Task<Option<task::TaskContext>> {
 8408        let position = Point::new(buffer_row, tasks.column);
 8409        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 8410        let location = Location {
 8411            buffer: buffer.clone(),
 8412            range: range_start..range_start,
 8413        };
 8414        // Fill in the environmental variables from the tree-sitter captures
 8415        let mut captured_task_variables = TaskVariables::default();
 8416        for (capture_name, value) in tasks.extra_variables.clone() {
 8417            captured_task_variables.insert(
 8418                task::VariableName::Custom(capture_name.into()),
 8419                value.clone(),
 8420            );
 8421        }
 8422        project.update(cx, |project, cx| {
 8423            project.task_store().update(cx, |task_store, cx| {
 8424                task_store.task_context_for_location(captured_task_variables, location, cx)
 8425            })
 8426        })
 8427    }
 8428
 8429    pub fn spawn_nearest_task(
 8430        &mut self,
 8431        action: &SpawnNearestTask,
 8432        window: &mut Window,
 8433        cx: &mut Context<Self>,
 8434    ) {
 8435        let Some((workspace, _)) = self.workspace.clone() else {
 8436            return;
 8437        };
 8438        let Some(project) = self.project.clone() else {
 8439            return;
 8440        };
 8441
 8442        // Try to find a closest, enclosing node using tree-sitter that has a task
 8443        let Some((buffer, buffer_row, tasks)) = self
 8444            .find_enclosing_node_task(cx)
 8445            // Or find the task that's closest in row-distance.
 8446            .or_else(|| self.find_closest_task(cx))
 8447        else {
 8448            return;
 8449        };
 8450
 8451        let reveal_strategy = action.reveal;
 8452        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 8453        cx.spawn_in(window, async move |_, cx| {
 8454            let context = task_context.await?;
 8455            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 8456
 8457            let resolved = &mut resolved_task.resolved;
 8458            resolved.reveal = reveal_strategy;
 8459
 8460            workspace
 8461                .update_in(cx, |workspace, window, cx| {
 8462                    workspace.schedule_resolved_task(
 8463                        task_source_kind,
 8464                        resolved_task,
 8465                        false,
 8466                        window,
 8467                        cx,
 8468                    );
 8469                })
 8470                .ok()
 8471        })
 8472        .detach();
 8473    }
 8474
 8475    fn find_closest_task(
 8476        &mut self,
 8477        cx: &mut Context<Self>,
 8478    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8479        let cursor_row = self
 8480            .selections
 8481            .newest_adjusted(&self.display_snapshot(cx))
 8482            .head()
 8483            .row;
 8484
 8485        let ((buffer_id, row), tasks) = self
 8486            .tasks
 8487            .iter()
 8488            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 8489
 8490        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 8491        let tasks = Arc::new(tasks.to_owned());
 8492        Some((buffer, *row, tasks))
 8493    }
 8494
 8495    fn find_enclosing_node_task(
 8496        &mut self,
 8497        cx: &mut Context<Self>,
 8498    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8499        let snapshot = self.buffer.read(cx).snapshot(cx);
 8500        let offset = self
 8501            .selections
 8502            .newest::<usize>(&self.display_snapshot(cx))
 8503            .head();
 8504        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 8505        let buffer_id = excerpt.buffer().remote_id();
 8506
 8507        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 8508        let mut cursor = layer.node().walk();
 8509
 8510        while cursor.goto_first_child_for_byte(offset).is_some() {
 8511            if cursor.node().end_byte() == offset {
 8512                cursor.goto_next_sibling();
 8513            }
 8514        }
 8515
 8516        // Ascend to the smallest ancestor that contains the range and has a task.
 8517        loop {
 8518            let node = cursor.node();
 8519            let node_range = node.byte_range();
 8520            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 8521
 8522            // Check if this node contains our offset
 8523            if node_range.start <= offset && node_range.end >= offset {
 8524                // If it contains offset, check for task
 8525                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 8526                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 8527                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 8528                }
 8529            }
 8530
 8531            if !cursor.goto_parent() {
 8532                break;
 8533            }
 8534        }
 8535        None
 8536    }
 8537
 8538    fn render_run_indicator(
 8539        &self,
 8540        _style: &EditorStyle,
 8541        is_active: bool,
 8542        row: DisplayRow,
 8543        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 8544        cx: &mut Context<Self>,
 8545    ) -> IconButton {
 8546        let color = Color::Muted;
 8547        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 8548
 8549        IconButton::new(
 8550            ("run_indicator", row.0 as usize),
 8551            ui::IconName::PlayOutlined,
 8552        )
 8553        .shape(ui::IconButtonShape::Square)
 8554        .icon_size(IconSize::XSmall)
 8555        .icon_color(color)
 8556        .toggle_state(is_active)
 8557        .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 8558            let quick_launch = match e {
 8559                ClickEvent::Keyboard(_) => true,
 8560                ClickEvent::Mouse(e) => e.down.button == MouseButton::Left,
 8561            };
 8562
 8563            window.focus(&editor.focus_handle(cx));
 8564            editor.toggle_code_actions(
 8565                &ToggleCodeActions {
 8566                    deployed_from: Some(CodeActionSource::RunMenu(row)),
 8567                    quick_launch,
 8568                },
 8569                window,
 8570                cx,
 8571            );
 8572        }))
 8573        .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8574            editor.set_breakpoint_context_menu(row, position, event.position(), window, cx);
 8575        }))
 8576    }
 8577
 8578    pub fn context_menu_visible(&self) -> bool {
 8579        !self.edit_prediction_preview_is_active()
 8580            && self
 8581                .context_menu
 8582                .borrow()
 8583                .as_ref()
 8584                .is_some_and(|menu| menu.visible())
 8585    }
 8586
 8587    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 8588        self.context_menu
 8589            .borrow()
 8590            .as_ref()
 8591            .map(|menu| menu.origin())
 8592    }
 8593
 8594    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 8595        self.context_menu_options = Some(options);
 8596    }
 8597
 8598    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = px(24.);
 8599    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = px(2.);
 8600
 8601    fn render_edit_prediction_popover(
 8602        &mut self,
 8603        text_bounds: &Bounds<Pixels>,
 8604        content_origin: gpui::Point<Pixels>,
 8605        right_margin: Pixels,
 8606        editor_snapshot: &EditorSnapshot,
 8607        visible_row_range: Range<DisplayRow>,
 8608        scroll_top: ScrollOffset,
 8609        scroll_bottom: ScrollOffset,
 8610        line_layouts: &[LineWithInvisibles],
 8611        line_height: Pixels,
 8612        scroll_position: gpui::Point<ScrollOffset>,
 8613        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8614        newest_selection_head: Option<DisplayPoint>,
 8615        editor_width: Pixels,
 8616        style: &EditorStyle,
 8617        window: &mut Window,
 8618        cx: &mut App,
 8619    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8620        if self.mode().is_minimap() {
 8621            return None;
 8622        }
 8623        let active_edit_prediction = self.active_edit_prediction.as_ref()?;
 8624
 8625        if self.edit_prediction_visible_in_cursor_popover(true) {
 8626            return None;
 8627        }
 8628
 8629        match &active_edit_prediction.completion {
 8630            EditPrediction::MoveWithin { target, .. } => {
 8631                let target_display_point = target.to_display_point(editor_snapshot);
 8632
 8633                if self.edit_prediction_requires_modifier() {
 8634                    if !self.edit_prediction_preview_is_active() {
 8635                        return None;
 8636                    }
 8637
 8638                    self.render_edit_prediction_modifier_jump_popover(
 8639                        text_bounds,
 8640                        content_origin,
 8641                        visible_row_range,
 8642                        line_layouts,
 8643                        line_height,
 8644                        scroll_pixel_position,
 8645                        newest_selection_head,
 8646                        target_display_point,
 8647                        window,
 8648                        cx,
 8649                    )
 8650                } else {
 8651                    self.render_edit_prediction_eager_jump_popover(
 8652                        text_bounds,
 8653                        content_origin,
 8654                        editor_snapshot,
 8655                        visible_row_range,
 8656                        scroll_top,
 8657                        scroll_bottom,
 8658                        line_height,
 8659                        scroll_pixel_position,
 8660                        target_display_point,
 8661                        editor_width,
 8662                        window,
 8663                        cx,
 8664                    )
 8665                }
 8666            }
 8667            EditPrediction::Edit {
 8668                display_mode: EditDisplayMode::Inline,
 8669                ..
 8670            } => None,
 8671            EditPrediction::Edit {
 8672                display_mode: EditDisplayMode::TabAccept,
 8673                edits,
 8674                ..
 8675            } => {
 8676                let range = &edits.first()?.0;
 8677                let target_display_point = range.end.to_display_point(editor_snapshot);
 8678
 8679                self.render_edit_prediction_end_of_line_popover(
 8680                    "Accept",
 8681                    editor_snapshot,
 8682                    visible_row_range,
 8683                    target_display_point,
 8684                    line_height,
 8685                    scroll_pixel_position,
 8686                    content_origin,
 8687                    editor_width,
 8688                    window,
 8689                    cx,
 8690                )
 8691            }
 8692            EditPrediction::Edit {
 8693                edits,
 8694                edit_preview,
 8695                display_mode: EditDisplayMode::DiffPopover,
 8696                snapshot,
 8697            } => self.render_edit_prediction_diff_popover(
 8698                text_bounds,
 8699                content_origin,
 8700                right_margin,
 8701                editor_snapshot,
 8702                visible_row_range,
 8703                line_layouts,
 8704                line_height,
 8705                scroll_position,
 8706                scroll_pixel_position,
 8707                newest_selection_head,
 8708                editor_width,
 8709                style,
 8710                edits,
 8711                edit_preview,
 8712                snapshot,
 8713                window,
 8714                cx,
 8715            ),
 8716            EditPrediction::MoveOutside { snapshot, .. } => {
 8717                let file_name = snapshot
 8718                    .file()
 8719                    .map(|file| file.file_name(cx))
 8720                    .unwrap_or("untitled");
 8721                let mut element = self
 8722                    .render_edit_prediction_line_popover(
 8723                        format!("Jump to {file_name}"),
 8724                        Some(IconName::ZedPredict),
 8725                        window,
 8726                        cx,
 8727                    )
 8728                    .into_any();
 8729
 8730                let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8731                let origin_x = text_bounds.size.width / 2. - size.width / 2.;
 8732                let origin_y = text_bounds.size.height - size.height - px(30.);
 8733                let origin = text_bounds.origin + gpui::Point::new(origin_x, origin_y);
 8734                element.prepaint_at(origin, window, cx);
 8735
 8736                Some((element, origin))
 8737            }
 8738        }
 8739    }
 8740
 8741    fn render_edit_prediction_modifier_jump_popover(
 8742        &mut self,
 8743        text_bounds: &Bounds<Pixels>,
 8744        content_origin: gpui::Point<Pixels>,
 8745        visible_row_range: Range<DisplayRow>,
 8746        line_layouts: &[LineWithInvisibles],
 8747        line_height: Pixels,
 8748        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8749        newest_selection_head: Option<DisplayPoint>,
 8750        target_display_point: DisplayPoint,
 8751        window: &mut Window,
 8752        cx: &mut App,
 8753    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8754        let scrolled_content_origin =
 8755            content_origin - gpui::Point::new(scroll_pixel_position.x.into(), Pixels::ZERO);
 8756
 8757        const SCROLL_PADDING_Y: Pixels = px(12.);
 8758
 8759        if target_display_point.row() < visible_row_range.start {
 8760            return self.render_edit_prediction_scroll_popover(
 8761                |_| SCROLL_PADDING_Y,
 8762                IconName::ArrowUp,
 8763                visible_row_range,
 8764                line_layouts,
 8765                newest_selection_head,
 8766                scrolled_content_origin,
 8767                window,
 8768                cx,
 8769            );
 8770        } else if target_display_point.row() >= visible_row_range.end {
 8771            return self.render_edit_prediction_scroll_popover(
 8772                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 8773                IconName::ArrowDown,
 8774                visible_row_range,
 8775                line_layouts,
 8776                newest_selection_head,
 8777                scrolled_content_origin,
 8778                window,
 8779                cx,
 8780            );
 8781        }
 8782
 8783        const POLE_WIDTH: Pixels = px(2.);
 8784
 8785        let line_layout =
 8786            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 8787        let target_column = target_display_point.column() as usize;
 8788
 8789        let target_x = line_layout.x_for_index(target_column);
 8790        let target_y = (target_display_point.row().as_f64() * f64::from(line_height))
 8791            - scroll_pixel_position.y;
 8792
 8793        let flag_on_right = target_x < text_bounds.size.width / 2.;
 8794
 8795        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 8796        border_color.l += 0.001;
 8797
 8798        let mut element = v_flex()
 8799            .items_end()
 8800            .when(flag_on_right, |el| el.items_start())
 8801            .child(if flag_on_right {
 8802                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 8803                    .rounded_bl(px(0.))
 8804                    .rounded_tl(px(0.))
 8805                    .border_l_2()
 8806                    .border_color(border_color)
 8807            } else {
 8808                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 8809                    .rounded_br(px(0.))
 8810                    .rounded_tr(px(0.))
 8811                    .border_r_2()
 8812                    .border_color(border_color)
 8813            })
 8814            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 8815            .into_any();
 8816
 8817        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8818
 8819        let mut origin = scrolled_content_origin + point(target_x, target_y.into())
 8820            - point(
 8821                if flag_on_right {
 8822                    POLE_WIDTH
 8823                } else {
 8824                    size.width - POLE_WIDTH
 8825                },
 8826                size.height - line_height,
 8827            );
 8828
 8829        origin.x = origin.x.max(content_origin.x);
 8830
 8831        element.prepaint_at(origin, window, cx);
 8832
 8833        Some((element, origin))
 8834    }
 8835
 8836    fn render_edit_prediction_scroll_popover(
 8837        &mut self,
 8838        to_y: impl Fn(Size<Pixels>) -> Pixels,
 8839        scroll_icon: IconName,
 8840        visible_row_range: Range<DisplayRow>,
 8841        line_layouts: &[LineWithInvisibles],
 8842        newest_selection_head: Option<DisplayPoint>,
 8843        scrolled_content_origin: gpui::Point<Pixels>,
 8844        window: &mut Window,
 8845        cx: &mut App,
 8846    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8847        let mut element = self
 8848            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)
 8849            .into_any();
 8850
 8851        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8852
 8853        let cursor = newest_selection_head?;
 8854        let cursor_row_layout =
 8855            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 8856        let cursor_column = cursor.column() as usize;
 8857
 8858        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 8859
 8860        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 8861
 8862        element.prepaint_at(origin, window, cx);
 8863        Some((element, origin))
 8864    }
 8865
 8866    fn render_edit_prediction_eager_jump_popover(
 8867        &mut self,
 8868        text_bounds: &Bounds<Pixels>,
 8869        content_origin: gpui::Point<Pixels>,
 8870        editor_snapshot: &EditorSnapshot,
 8871        visible_row_range: Range<DisplayRow>,
 8872        scroll_top: ScrollOffset,
 8873        scroll_bottom: ScrollOffset,
 8874        line_height: Pixels,
 8875        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8876        target_display_point: DisplayPoint,
 8877        editor_width: Pixels,
 8878        window: &mut Window,
 8879        cx: &mut App,
 8880    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8881        if target_display_point.row().as_f64() < scroll_top {
 8882            let mut element = self
 8883                .render_edit_prediction_line_popover(
 8884                    "Jump to Edit",
 8885                    Some(IconName::ArrowUp),
 8886                    window,
 8887                    cx,
 8888                )
 8889                .into_any();
 8890
 8891            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8892            let offset = point(
 8893                (text_bounds.size.width - size.width) / 2.,
 8894                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8895            );
 8896
 8897            let origin = text_bounds.origin + offset;
 8898            element.prepaint_at(origin, window, cx);
 8899            Some((element, origin))
 8900        } else if (target_display_point.row().as_f64() + 1.) > scroll_bottom {
 8901            let mut element = self
 8902                .render_edit_prediction_line_popover(
 8903                    "Jump to Edit",
 8904                    Some(IconName::ArrowDown),
 8905                    window,
 8906                    cx,
 8907                )
 8908                .into_any();
 8909
 8910            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8911            let offset = point(
 8912                (text_bounds.size.width - size.width) / 2.,
 8913                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8914            );
 8915
 8916            let origin = text_bounds.origin + offset;
 8917            element.prepaint_at(origin, window, cx);
 8918            Some((element, origin))
 8919        } else {
 8920            self.render_edit_prediction_end_of_line_popover(
 8921                "Jump to Edit",
 8922                editor_snapshot,
 8923                visible_row_range,
 8924                target_display_point,
 8925                line_height,
 8926                scroll_pixel_position,
 8927                content_origin,
 8928                editor_width,
 8929                window,
 8930                cx,
 8931            )
 8932        }
 8933    }
 8934
 8935    fn render_edit_prediction_end_of_line_popover(
 8936        self: &mut Editor,
 8937        label: &'static str,
 8938        editor_snapshot: &EditorSnapshot,
 8939        visible_row_range: Range<DisplayRow>,
 8940        target_display_point: DisplayPoint,
 8941        line_height: Pixels,
 8942        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8943        content_origin: gpui::Point<Pixels>,
 8944        editor_width: Pixels,
 8945        window: &mut Window,
 8946        cx: &mut App,
 8947    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8948        let target_line_end = DisplayPoint::new(
 8949            target_display_point.row(),
 8950            editor_snapshot.line_len(target_display_point.row()),
 8951        );
 8952
 8953        let mut element = self
 8954            .render_edit_prediction_line_popover(label, None, window, cx)
 8955            .into_any();
 8956
 8957        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8958
 8959        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 8960
 8961        let start_point = content_origin - point(scroll_pixel_position.x.into(), Pixels::ZERO);
 8962        let mut origin = start_point
 8963            + line_origin
 8964            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 8965        origin.x = origin.x.max(content_origin.x);
 8966
 8967        let max_x = content_origin.x + editor_width - size.width;
 8968
 8969        if origin.x > max_x {
 8970            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 8971
 8972            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 8973                origin.y += offset;
 8974                IconName::ArrowUp
 8975            } else {
 8976                origin.y -= offset;
 8977                IconName::ArrowDown
 8978            };
 8979
 8980            element = self
 8981                .render_edit_prediction_line_popover(label, Some(icon), window, cx)
 8982                .into_any();
 8983
 8984            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8985
 8986            origin.x = content_origin.x + editor_width - size.width - px(2.);
 8987        }
 8988
 8989        element.prepaint_at(origin, window, cx);
 8990        Some((element, origin))
 8991    }
 8992
 8993    fn render_edit_prediction_diff_popover(
 8994        self: &Editor,
 8995        text_bounds: &Bounds<Pixels>,
 8996        content_origin: gpui::Point<Pixels>,
 8997        right_margin: Pixels,
 8998        editor_snapshot: &EditorSnapshot,
 8999        visible_row_range: Range<DisplayRow>,
 9000        line_layouts: &[LineWithInvisibles],
 9001        line_height: Pixels,
 9002        scroll_position: gpui::Point<ScrollOffset>,
 9003        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9004        newest_selection_head: Option<DisplayPoint>,
 9005        editor_width: Pixels,
 9006        style: &EditorStyle,
 9007        edits: &Vec<(Range<Anchor>, Arc<str>)>,
 9008        edit_preview: &Option<language::EditPreview>,
 9009        snapshot: &language::BufferSnapshot,
 9010        window: &mut Window,
 9011        cx: &mut App,
 9012    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9013        let edit_start = edits
 9014            .first()
 9015            .unwrap()
 9016            .0
 9017            .start
 9018            .to_display_point(editor_snapshot);
 9019        let edit_end = edits
 9020            .last()
 9021            .unwrap()
 9022            .0
 9023            .end
 9024            .to_display_point(editor_snapshot);
 9025
 9026        let is_visible = visible_row_range.contains(&edit_start.row())
 9027            || visible_row_range.contains(&edit_end.row());
 9028        if !is_visible {
 9029            return None;
 9030        }
 9031
 9032        let highlighted_edits = if let Some(edit_preview) = edit_preview.as_ref() {
 9033            crate::edit_prediction_edit_text(snapshot, edits, edit_preview, false, cx)
 9034        } else {
 9035            // Fallback for providers without edit_preview
 9036            crate::edit_prediction_fallback_text(edits, cx)
 9037        };
 9038
 9039        let styled_text = highlighted_edits.to_styled_text(&style.text);
 9040        let line_count = highlighted_edits.text.lines().count();
 9041
 9042        const BORDER_WIDTH: Pixels = px(1.);
 9043
 9044        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9045        let has_keybind = keybind.is_some();
 9046
 9047        let mut element = h_flex()
 9048            .items_start()
 9049            .child(
 9050                h_flex()
 9051                    .bg(cx.theme().colors().editor_background)
 9052                    .border(BORDER_WIDTH)
 9053                    .shadow_xs()
 9054                    .border_color(cx.theme().colors().border)
 9055                    .rounded_l_lg()
 9056                    .when(line_count > 1, |el| el.rounded_br_lg())
 9057                    .pr_1()
 9058                    .child(styled_text),
 9059            )
 9060            .child(
 9061                h_flex()
 9062                    .h(line_height + BORDER_WIDTH * 2.)
 9063                    .px_1p5()
 9064                    .gap_1()
 9065                    // Workaround: For some reason, there's a gap if we don't do this
 9066                    .ml(-BORDER_WIDTH)
 9067                    .shadow(vec![gpui::BoxShadow {
 9068                        color: gpui::black().opacity(0.05),
 9069                        offset: point(px(1.), px(1.)),
 9070                        blur_radius: px(2.),
 9071                        spread_radius: px(0.),
 9072                    }])
 9073                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 9074                    .border(BORDER_WIDTH)
 9075                    .border_color(cx.theme().colors().border)
 9076                    .rounded_r_lg()
 9077                    .id("edit_prediction_diff_popover_keybind")
 9078                    .when(!has_keybind, |el| {
 9079                        let status_colors = cx.theme().status();
 9080
 9081                        el.bg(status_colors.error_background)
 9082                            .border_color(status_colors.error.opacity(0.6))
 9083                            .child(Icon::new(IconName::Info).color(Color::Error))
 9084                            .cursor_default()
 9085                            .hoverable_tooltip(move |_window, cx| {
 9086                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9087                            })
 9088                    })
 9089                    .children(keybind),
 9090            )
 9091            .into_any();
 9092
 9093        let longest_row =
 9094            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 9095        let longest_line_width = if visible_row_range.contains(&longest_row) {
 9096            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 9097        } else {
 9098            layout_line(
 9099                longest_row,
 9100                editor_snapshot,
 9101                style,
 9102                editor_width,
 9103                |_| false,
 9104                window,
 9105                cx,
 9106            )
 9107            .width
 9108        };
 9109
 9110        let viewport_bounds =
 9111            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 9112                right: -right_margin,
 9113                ..Default::default()
 9114            });
 9115
 9116        let x_after_longest = Pixels::from(
 9117            ScrollPixelOffset::from(
 9118                text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X,
 9119            ) - scroll_pixel_position.x,
 9120        );
 9121
 9122        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9123
 9124        // Fully visible if it can be displayed within the window (allow overlapping other
 9125        // panes). However, this is only allowed if the popover starts within text_bounds.
 9126        let can_position_to_the_right = x_after_longest < text_bounds.right()
 9127            && x_after_longest + element_bounds.width < viewport_bounds.right();
 9128
 9129        let mut origin = if can_position_to_the_right {
 9130            point(
 9131                x_after_longest,
 9132                text_bounds.origin.y
 9133                    + Pixels::from(
 9134                        edit_start.row().as_f64() * ScrollPixelOffset::from(line_height)
 9135                            - scroll_pixel_position.y,
 9136                    ),
 9137            )
 9138        } else {
 9139            let cursor_row = newest_selection_head.map(|head| head.row());
 9140            let above_edit = edit_start
 9141                .row()
 9142                .0
 9143                .checked_sub(line_count as u32)
 9144                .map(DisplayRow);
 9145            let below_edit = Some(edit_end.row() + 1);
 9146            let above_cursor =
 9147                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 9148            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 9149
 9150            // Place the edit popover adjacent to the edit if there is a location
 9151            // available that is onscreen and does not obscure the cursor. Otherwise,
 9152            // place it adjacent to the cursor.
 9153            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 9154                .into_iter()
 9155                .flatten()
 9156                .find(|&start_row| {
 9157                    let end_row = start_row + line_count as u32;
 9158                    visible_row_range.contains(&start_row)
 9159                        && visible_row_range.contains(&end_row)
 9160                        && cursor_row
 9161                            .is_none_or(|cursor_row| !((start_row..end_row).contains(&cursor_row)))
 9162                })?;
 9163
 9164            content_origin
 9165                + point(
 9166                    Pixels::from(-scroll_pixel_position.x),
 9167                    Pixels::from(
 9168                        (row_target.as_f64() - scroll_position.y) * f64::from(line_height),
 9169                    ),
 9170                )
 9171        };
 9172
 9173        origin.x -= BORDER_WIDTH;
 9174
 9175        window.defer_draw(element, origin, 1);
 9176
 9177        // Do not return an element, since it will already be drawn due to defer_draw.
 9178        None
 9179    }
 9180
 9181    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 9182        px(30.)
 9183    }
 9184
 9185    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 9186        if self.read_only(cx) {
 9187            cx.theme().players().read_only()
 9188        } else {
 9189            self.style.as_ref().unwrap().local_player
 9190        }
 9191    }
 9192
 9193    fn render_edit_prediction_accept_keybind(
 9194        &self,
 9195        window: &mut Window,
 9196        cx: &mut App,
 9197    ) -> Option<AnyElement> {
 9198        let accept_binding = self.accept_edit_prediction_keybind(false, window, cx);
 9199        let accept_keystroke = accept_binding.keystroke()?;
 9200
 9201        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9202
 9203        let modifiers_color = if *accept_keystroke.modifiers() == window.modifiers() {
 9204            Color::Accent
 9205        } else {
 9206            Color::Muted
 9207        };
 9208
 9209        h_flex()
 9210            .px_0p5()
 9211            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 9212            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9213            .text_size(TextSize::XSmall.rems(cx))
 9214            .child(h_flex().children(ui::render_modifiers(
 9215                accept_keystroke.modifiers(),
 9216                PlatformStyle::platform(),
 9217                Some(modifiers_color),
 9218                Some(IconSize::XSmall.rems().into()),
 9219                true,
 9220            )))
 9221            .when(is_platform_style_mac, |parent| {
 9222                parent.child(accept_keystroke.key().to_string())
 9223            })
 9224            .when(!is_platform_style_mac, |parent| {
 9225                parent.child(
 9226                    Key::new(
 9227                        util::capitalize(accept_keystroke.key()),
 9228                        Some(Color::Default),
 9229                    )
 9230                    .size(Some(IconSize::XSmall.rems().into())),
 9231                )
 9232            })
 9233            .into_any()
 9234            .into()
 9235    }
 9236
 9237    fn render_edit_prediction_line_popover(
 9238        &self,
 9239        label: impl Into<SharedString>,
 9240        icon: Option<IconName>,
 9241        window: &mut Window,
 9242        cx: &mut App,
 9243    ) -> Stateful<Div> {
 9244        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 9245
 9246        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9247        let has_keybind = keybind.is_some();
 9248
 9249        h_flex()
 9250            .id("ep-line-popover")
 9251            .py_0p5()
 9252            .pl_1()
 9253            .pr(padding_right)
 9254            .gap_1()
 9255            .rounded_md()
 9256            .border_1()
 9257            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9258            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9259            .shadow_xs()
 9260            .when(!has_keybind, |el| {
 9261                let status_colors = cx.theme().status();
 9262
 9263                el.bg(status_colors.error_background)
 9264                    .border_color(status_colors.error.opacity(0.6))
 9265                    .pl_2()
 9266                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9267                    .cursor_default()
 9268                    .hoverable_tooltip(move |_window, cx| {
 9269                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9270                    })
 9271            })
 9272            .children(keybind)
 9273            .child(
 9274                Label::new(label)
 9275                    .size(LabelSize::Small)
 9276                    .when(!has_keybind, |el| {
 9277                        el.color(cx.theme().status().error.into()).strikethrough()
 9278                    }),
 9279            )
 9280            .when(!has_keybind, |el| {
 9281                el.child(
 9282                    h_flex().ml_1().child(
 9283                        Icon::new(IconName::Info)
 9284                            .size(IconSize::Small)
 9285                            .color(cx.theme().status().error.into()),
 9286                    ),
 9287                )
 9288            })
 9289            .when_some(icon, |element, icon| {
 9290                element.child(
 9291                    div()
 9292                        .mt(px(1.5))
 9293                        .child(Icon::new(icon).size(IconSize::Small)),
 9294                )
 9295            })
 9296    }
 9297
 9298    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 9299        let accent_color = cx.theme().colors().text_accent;
 9300        let editor_bg_color = cx.theme().colors().editor_background;
 9301        editor_bg_color.blend(accent_color.opacity(0.1))
 9302    }
 9303
 9304    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 9305        let accent_color = cx.theme().colors().text_accent;
 9306        let editor_bg_color = cx.theme().colors().editor_background;
 9307        editor_bg_color.blend(accent_color.opacity(0.6))
 9308    }
 9309    fn get_prediction_provider_icon_name(
 9310        provider: &Option<RegisteredEditPredictionProvider>,
 9311    ) -> IconName {
 9312        match provider {
 9313            Some(provider) => match provider.provider.name() {
 9314                "copilot" => IconName::Copilot,
 9315                "supermaven" => IconName::Supermaven,
 9316                _ => IconName::ZedPredict,
 9317            },
 9318            None => IconName::ZedPredict,
 9319        }
 9320    }
 9321
 9322    fn render_edit_prediction_cursor_popover(
 9323        &self,
 9324        min_width: Pixels,
 9325        max_width: Pixels,
 9326        cursor_point: Point,
 9327        style: &EditorStyle,
 9328        accept_keystroke: Option<&gpui::KeybindingKeystroke>,
 9329        _window: &Window,
 9330        cx: &mut Context<Editor>,
 9331    ) -> Option<AnyElement> {
 9332        let provider = self.edit_prediction_provider.as_ref()?;
 9333        let provider_icon = Self::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9334
 9335        let is_refreshing = provider.provider.is_refreshing(cx);
 9336
 9337        fn pending_completion_container(icon: IconName) -> Div {
 9338            h_flex().h_full().flex_1().gap_2().child(Icon::new(icon))
 9339        }
 9340
 9341        let completion = match &self.active_edit_prediction {
 9342            Some(prediction) => {
 9343                if !self.has_visible_completions_menu() {
 9344                    const RADIUS: Pixels = px(6.);
 9345                    const BORDER_WIDTH: Pixels = px(1.);
 9346
 9347                    return Some(
 9348                        h_flex()
 9349                            .elevation_2(cx)
 9350                            .border(BORDER_WIDTH)
 9351                            .border_color(cx.theme().colors().border)
 9352                            .when(accept_keystroke.is_none(), |el| {
 9353                                el.border_color(cx.theme().status().error)
 9354                            })
 9355                            .rounded(RADIUS)
 9356                            .rounded_tl(px(0.))
 9357                            .overflow_hidden()
 9358                            .child(div().px_1p5().child(match &prediction.completion {
 9359                                EditPrediction::MoveWithin { target, snapshot } => {
 9360                                    use text::ToPoint as _;
 9361                                    if target.text_anchor.to_point(snapshot).row > cursor_point.row
 9362                                    {
 9363                                        Icon::new(IconName::ZedPredictDown)
 9364                                    } else {
 9365                                        Icon::new(IconName::ZedPredictUp)
 9366                                    }
 9367                                }
 9368                                EditPrediction::MoveOutside { .. } => {
 9369                                    // TODO [zeta2] custom icon for external jump?
 9370                                    Icon::new(provider_icon)
 9371                                }
 9372                                EditPrediction::Edit { .. } => Icon::new(provider_icon),
 9373                            }))
 9374                            .child(
 9375                                h_flex()
 9376                                    .gap_1()
 9377                                    .py_1()
 9378                                    .px_2()
 9379                                    .rounded_r(RADIUS - BORDER_WIDTH)
 9380                                    .border_l_1()
 9381                                    .border_color(cx.theme().colors().border)
 9382                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9383                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 9384                                        el.child(
 9385                                            Label::new("Hold")
 9386                                                .size(LabelSize::Small)
 9387                                                .when(accept_keystroke.is_none(), |el| {
 9388                                                    el.strikethrough()
 9389                                                })
 9390                                                .line_height_style(LineHeightStyle::UiLabel),
 9391                                        )
 9392                                    })
 9393                                    .id("edit_prediction_cursor_popover_keybind")
 9394                                    .when(accept_keystroke.is_none(), |el| {
 9395                                        let status_colors = cx.theme().status();
 9396
 9397                                        el.bg(status_colors.error_background)
 9398                                            .border_color(status_colors.error.opacity(0.6))
 9399                                            .child(Icon::new(IconName::Info).color(Color::Error))
 9400                                            .cursor_default()
 9401                                            .hoverable_tooltip(move |_window, cx| {
 9402                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 9403                                                    .into()
 9404                                            })
 9405                                    })
 9406                                    .when_some(
 9407                                        accept_keystroke.as_ref(),
 9408                                        |el, accept_keystroke| {
 9409                                            el.child(h_flex().children(ui::render_modifiers(
 9410                                                accept_keystroke.modifiers(),
 9411                                                PlatformStyle::platform(),
 9412                                                Some(Color::Default),
 9413                                                Some(IconSize::XSmall.rems().into()),
 9414                                                false,
 9415                                            )))
 9416                                        },
 9417                                    ),
 9418                            )
 9419                            .into_any(),
 9420                    );
 9421                }
 9422
 9423                self.render_edit_prediction_cursor_popover_preview(
 9424                    prediction,
 9425                    cursor_point,
 9426                    style,
 9427                    cx,
 9428                )?
 9429            }
 9430
 9431            None if is_refreshing => match &self.stale_edit_prediction_in_menu {
 9432                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 9433                    stale_completion,
 9434                    cursor_point,
 9435                    style,
 9436                    cx,
 9437                )?,
 9438
 9439                None => pending_completion_container(provider_icon)
 9440                    .child(Label::new("...").size(LabelSize::Small)),
 9441            },
 9442
 9443            None => pending_completion_container(provider_icon)
 9444                .child(Label::new("...").size(LabelSize::Small)),
 9445        };
 9446
 9447        let completion = if is_refreshing || self.active_edit_prediction.is_none() {
 9448            completion
 9449                .with_animation(
 9450                    "loading-completion",
 9451                    Animation::new(Duration::from_secs(2))
 9452                        .repeat()
 9453                        .with_easing(pulsating_between(0.4, 0.8)),
 9454                    |label, delta| label.opacity(delta),
 9455                )
 9456                .into_any_element()
 9457        } else {
 9458            completion.into_any_element()
 9459        };
 9460
 9461        let has_completion = self.active_edit_prediction.is_some();
 9462
 9463        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9464        Some(
 9465            h_flex()
 9466                .min_w(min_width)
 9467                .max_w(max_width)
 9468                .flex_1()
 9469                .elevation_2(cx)
 9470                .border_color(cx.theme().colors().border)
 9471                .child(
 9472                    div()
 9473                        .flex_1()
 9474                        .py_1()
 9475                        .px_2()
 9476                        .overflow_hidden()
 9477                        .child(completion),
 9478                )
 9479                .when_some(accept_keystroke, |el, accept_keystroke| {
 9480                    if !accept_keystroke.modifiers().modified() {
 9481                        return el;
 9482                    }
 9483
 9484                    el.child(
 9485                        h_flex()
 9486                            .h_full()
 9487                            .border_l_1()
 9488                            .rounded_r_lg()
 9489                            .border_color(cx.theme().colors().border)
 9490                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9491                            .gap_1()
 9492                            .py_1()
 9493                            .px_2()
 9494                            .child(
 9495                                h_flex()
 9496                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9497                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 9498                                    .child(h_flex().children(ui::render_modifiers(
 9499                                        accept_keystroke.modifiers(),
 9500                                        PlatformStyle::platform(),
 9501                                        Some(if !has_completion {
 9502                                            Color::Muted
 9503                                        } else {
 9504                                            Color::Default
 9505                                        }),
 9506                                        None,
 9507                                        false,
 9508                                    ))),
 9509                            )
 9510                            .child(Label::new("Preview").into_any_element())
 9511                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 9512                    )
 9513                })
 9514                .into_any(),
 9515        )
 9516    }
 9517
 9518    fn render_edit_prediction_cursor_popover_preview(
 9519        &self,
 9520        completion: &EditPredictionState,
 9521        cursor_point: Point,
 9522        style: &EditorStyle,
 9523        cx: &mut Context<Editor>,
 9524    ) -> Option<Div> {
 9525        use text::ToPoint as _;
 9526
 9527        fn render_relative_row_jump(
 9528            prefix: impl Into<String>,
 9529            current_row: u32,
 9530            target_row: u32,
 9531        ) -> Div {
 9532            let (row_diff, arrow) = if target_row < current_row {
 9533                (current_row - target_row, IconName::ArrowUp)
 9534            } else {
 9535                (target_row - current_row, IconName::ArrowDown)
 9536            };
 9537
 9538            h_flex()
 9539                .child(
 9540                    Label::new(format!("{}{}", prefix.into(), row_diff))
 9541                        .color(Color::Muted)
 9542                        .size(LabelSize::Small),
 9543                )
 9544                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 9545        }
 9546
 9547        let supports_jump = self
 9548            .edit_prediction_provider
 9549            .as_ref()
 9550            .map(|provider| provider.provider.supports_jump_to_edit())
 9551            .unwrap_or(true);
 9552
 9553        match &completion.completion {
 9554            EditPrediction::MoveWithin {
 9555                target, snapshot, ..
 9556            } => {
 9557                if !supports_jump {
 9558                    return None;
 9559                }
 9560
 9561                Some(
 9562                    h_flex()
 9563                        .px_2()
 9564                        .gap_2()
 9565                        .flex_1()
 9566                        .child(
 9567                            if target.text_anchor.to_point(snapshot).row > cursor_point.row {
 9568                                Icon::new(IconName::ZedPredictDown)
 9569                            } else {
 9570                                Icon::new(IconName::ZedPredictUp)
 9571                            },
 9572                        )
 9573                        .child(Label::new("Jump to Edit")),
 9574                )
 9575            }
 9576            EditPrediction::MoveOutside { snapshot, .. } => {
 9577                let file_name = snapshot
 9578                    .file()
 9579                    .map(|file| file.file_name(cx))
 9580                    .unwrap_or("untitled");
 9581                Some(
 9582                    h_flex()
 9583                        .px_2()
 9584                        .gap_2()
 9585                        .flex_1()
 9586                        .child(Icon::new(IconName::ZedPredict))
 9587                        .child(Label::new(format!("Jump to {file_name}"))),
 9588                )
 9589            }
 9590            EditPrediction::Edit {
 9591                edits,
 9592                edit_preview,
 9593                snapshot,
 9594                display_mode: _,
 9595            } => {
 9596                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(snapshot).row;
 9597
 9598                let (highlighted_edits, has_more_lines) =
 9599                    if let Some(edit_preview) = edit_preview.as_ref() {
 9600                        crate::edit_prediction_edit_text(snapshot, edits, edit_preview, true, cx)
 9601                            .first_line_preview()
 9602                    } else {
 9603                        crate::edit_prediction_fallback_text(edits, cx).first_line_preview()
 9604                    };
 9605
 9606                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 9607                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 9608
 9609                let preview = h_flex()
 9610                    .gap_1()
 9611                    .min_w_16()
 9612                    .child(styled_text)
 9613                    .when(has_more_lines, |parent| parent.child(""));
 9614
 9615                let left = if supports_jump && first_edit_row != cursor_point.row {
 9616                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 9617                        .into_any_element()
 9618                } else {
 9619                    let icon_name =
 9620                        Editor::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9621                    Icon::new(icon_name).into_any_element()
 9622                };
 9623
 9624                Some(
 9625                    h_flex()
 9626                        .h_full()
 9627                        .flex_1()
 9628                        .gap_2()
 9629                        .pr_1()
 9630                        .overflow_x_hidden()
 9631                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9632                        .child(left)
 9633                        .child(preview),
 9634                )
 9635            }
 9636        }
 9637    }
 9638
 9639    pub fn render_context_menu(
 9640        &self,
 9641        style: &EditorStyle,
 9642        max_height_in_lines: u32,
 9643        window: &mut Window,
 9644        cx: &mut Context<Editor>,
 9645    ) -> Option<AnyElement> {
 9646        let menu = self.context_menu.borrow();
 9647        let menu = menu.as_ref()?;
 9648        if !menu.visible() {
 9649            return None;
 9650        };
 9651        Some(menu.render(style, max_height_in_lines, window, cx))
 9652    }
 9653
 9654    fn render_context_menu_aside(
 9655        &mut self,
 9656        max_size: Size<Pixels>,
 9657        window: &mut Window,
 9658        cx: &mut Context<Editor>,
 9659    ) -> Option<AnyElement> {
 9660        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 9661            if menu.visible() {
 9662                menu.render_aside(max_size, window, cx)
 9663            } else {
 9664                None
 9665            }
 9666        })
 9667    }
 9668
 9669    fn hide_context_menu(
 9670        &mut self,
 9671        window: &mut Window,
 9672        cx: &mut Context<Self>,
 9673    ) -> Option<CodeContextMenu> {
 9674        cx.notify();
 9675        self.completion_tasks.clear();
 9676        let context_menu = self.context_menu.borrow_mut().take();
 9677        self.stale_edit_prediction_in_menu.take();
 9678        self.update_visible_edit_prediction(window, cx);
 9679        if let Some(CodeContextMenu::Completions(_)) = &context_menu
 9680            && let Some(completion_provider) = &self.completion_provider
 9681        {
 9682            completion_provider.selection_changed(None, window, cx);
 9683        }
 9684        context_menu
 9685    }
 9686
 9687    fn show_snippet_choices(
 9688        &mut self,
 9689        choices: &Vec<String>,
 9690        selection: Range<Anchor>,
 9691        cx: &mut Context<Self>,
 9692    ) {
 9693        let Some((_, buffer, _)) = self
 9694            .buffer()
 9695            .read(cx)
 9696            .excerpt_containing(selection.start, cx)
 9697        else {
 9698            return;
 9699        };
 9700        let Some((_, end_buffer, _)) = self.buffer().read(cx).excerpt_containing(selection.end, cx)
 9701        else {
 9702            return;
 9703        };
 9704        if buffer != end_buffer {
 9705            log::error!("expected anchor range to have matching buffer IDs");
 9706            return;
 9707        }
 9708
 9709        let id = post_inc(&mut self.next_completion_id);
 9710        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 9711        *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 9712            CompletionsMenu::new_snippet_choices(
 9713                id,
 9714                true,
 9715                choices,
 9716                selection,
 9717                buffer,
 9718                snippet_sort_order,
 9719            ),
 9720        ));
 9721    }
 9722
 9723    pub fn insert_snippet(
 9724        &mut self,
 9725        insertion_ranges: &[Range<usize>],
 9726        snippet: Snippet,
 9727        window: &mut Window,
 9728        cx: &mut Context<Self>,
 9729    ) -> Result<()> {
 9730        struct Tabstop<T> {
 9731            is_end_tabstop: bool,
 9732            ranges: Vec<Range<T>>,
 9733            choices: Option<Vec<String>>,
 9734        }
 9735
 9736        let tabstops = self.buffer.update(cx, |buffer, cx| {
 9737            let snippet_text: Arc<str> = snippet.text.clone().into();
 9738            let edits = insertion_ranges
 9739                .iter()
 9740                .cloned()
 9741                .map(|range| (range, snippet_text.clone()));
 9742            let autoindent_mode = AutoindentMode::Block {
 9743                original_indent_columns: Vec::new(),
 9744            };
 9745            buffer.edit(edits, Some(autoindent_mode), cx);
 9746
 9747            let snapshot = &*buffer.read(cx);
 9748            let snippet = &snippet;
 9749            snippet
 9750                .tabstops
 9751                .iter()
 9752                .map(|tabstop| {
 9753                    let is_end_tabstop = tabstop.ranges.first().is_some_and(|tabstop| {
 9754                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 9755                    });
 9756                    let mut tabstop_ranges = tabstop
 9757                        .ranges
 9758                        .iter()
 9759                        .flat_map(|tabstop_range| {
 9760                            let mut delta = 0_isize;
 9761                            insertion_ranges.iter().map(move |insertion_range| {
 9762                                let insertion_start = insertion_range.start as isize + delta;
 9763                                delta +=
 9764                                    snippet.text.len() as isize - insertion_range.len() as isize;
 9765
 9766                                let start = ((insertion_start + tabstop_range.start) as usize)
 9767                                    .min(snapshot.len());
 9768                                let end = ((insertion_start + tabstop_range.end) as usize)
 9769                                    .min(snapshot.len());
 9770                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 9771                            })
 9772                        })
 9773                        .collect::<Vec<_>>();
 9774                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 9775
 9776                    Tabstop {
 9777                        is_end_tabstop,
 9778                        ranges: tabstop_ranges,
 9779                        choices: tabstop.choices.clone(),
 9780                    }
 9781                })
 9782                .collect::<Vec<_>>()
 9783        });
 9784        if let Some(tabstop) = tabstops.first() {
 9785            self.change_selections(Default::default(), window, cx, |s| {
 9786                // Reverse order so that the first range is the newest created selection.
 9787                // Completions will use it and autoscroll will prioritize it.
 9788                s.select_ranges(tabstop.ranges.iter().rev().cloned());
 9789            });
 9790
 9791            if let Some(choices) = &tabstop.choices
 9792                && let Some(selection) = tabstop.ranges.first()
 9793            {
 9794                self.show_snippet_choices(choices, selection.clone(), cx)
 9795            }
 9796
 9797            // If we're already at the last tabstop and it's at the end of the snippet,
 9798            // we're done, we don't need to keep the state around.
 9799            if !tabstop.is_end_tabstop {
 9800                let choices = tabstops
 9801                    .iter()
 9802                    .map(|tabstop| tabstop.choices.clone())
 9803                    .collect();
 9804
 9805                let ranges = tabstops
 9806                    .into_iter()
 9807                    .map(|tabstop| tabstop.ranges)
 9808                    .collect::<Vec<_>>();
 9809
 9810                self.snippet_stack.push(SnippetState {
 9811                    active_index: 0,
 9812                    ranges,
 9813                    choices,
 9814                });
 9815            }
 9816
 9817            // Check whether the just-entered snippet ends with an auto-closable bracket.
 9818            if self.autoclose_regions.is_empty() {
 9819                let snapshot = self.buffer.read(cx).snapshot(cx);
 9820                for selection in &mut self.selections.all::<Point>(&self.display_snapshot(cx)) {
 9821                    let selection_head = selection.head();
 9822                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 9823                        continue;
 9824                    };
 9825
 9826                    let mut bracket_pair = None;
 9827                    let max_lookup_length = scope
 9828                        .brackets()
 9829                        .map(|(pair, _)| {
 9830                            pair.start
 9831                                .as_str()
 9832                                .chars()
 9833                                .count()
 9834                                .max(pair.end.as_str().chars().count())
 9835                        })
 9836                        .max();
 9837                    if let Some(max_lookup_length) = max_lookup_length {
 9838                        let next_text = snapshot
 9839                            .chars_at(selection_head)
 9840                            .take(max_lookup_length)
 9841                            .collect::<String>();
 9842                        let prev_text = snapshot
 9843                            .reversed_chars_at(selection_head)
 9844                            .take(max_lookup_length)
 9845                            .collect::<String>();
 9846
 9847                        for (pair, enabled) in scope.brackets() {
 9848                            if enabled
 9849                                && pair.close
 9850                                && prev_text.starts_with(pair.start.as_str())
 9851                                && next_text.starts_with(pair.end.as_str())
 9852                            {
 9853                                bracket_pair = Some(pair.clone());
 9854                                break;
 9855                            }
 9856                        }
 9857                    }
 9858
 9859                    if let Some(pair) = bracket_pair {
 9860                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 9861                        let autoclose_enabled =
 9862                            self.use_autoclose && snapshot_settings.use_autoclose;
 9863                        if autoclose_enabled {
 9864                            let start = snapshot.anchor_after(selection_head);
 9865                            let end = snapshot.anchor_after(selection_head);
 9866                            self.autoclose_regions.push(AutocloseRegion {
 9867                                selection_id: selection.id,
 9868                                range: start..end,
 9869                                pair,
 9870                            });
 9871                        }
 9872                    }
 9873                }
 9874            }
 9875        }
 9876        Ok(())
 9877    }
 9878
 9879    pub fn move_to_next_snippet_tabstop(
 9880        &mut self,
 9881        window: &mut Window,
 9882        cx: &mut Context<Self>,
 9883    ) -> bool {
 9884        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 9885    }
 9886
 9887    pub fn move_to_prev_snippet_tabstop(
 9888        &mut self,
 9889        window: &mut Window,
 9890        cx: &mut Context<Self>,
 9891    ) -> bool {
 9892        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 9893    }
 9894
 9895    pub fn move_to_snippet_tabstop(
 9896        &mut self,
 9897        bias: Bias,
 9898        window: &mut Window,
 9899        cx: &mut Context<Self>,
 9900    ) -> bool {
 9901        if let Some(mut snippet) = self.snippet_stack.pop() {
 9902            match bias {
 9903                Bias::Left => {
 9904                    if snippet.active_index > 0 {
 9905                        snippet.active_index -= 1;
 9906                    } else {
 9907                        self.snippet_stack.push(snippet);
 9908                        return false;
 9909                    }
 9910                }
 9911                Bias::Right => {
 9912                    if snippet.active_index + 1 < snippet.ranges.len() {
 9913                        snippet.active_index += 1;
 9914                    } else {
 9915                        self.snippet_stack.push(snippet);
 9916                        return false;
 9917                    }
 9918                }
 9919            }
 9920            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 9921                self.change_selections(Default::default(), window, cx, |s| {
 9922                    // Reverse order so that the first range is the newest created selection.
 9923                    // Completions will use it and autoscroll will prioritize it.
 9924                    s.select_ranges(current_ranges.iter().rev().cloned())
 9925                });
 9926
 9927                if let Some(choices) = &snippet.choices[snippet.active_index]
 9928                    && let Some(selection) = current_ranges.first()
 9929                {
 9930                    self.show_snippet_choices(choices, selection.clone(), cx);
 9931                }
 9932
 9933                // If snippet state is not at the last tabstop, push it back on the stack
 9934                if snippet.active_index + 1 < snippet.ranges.len() {
 9935                    self.snippet_stack.push(snippet);
 9936                }
 9937                return true;
 9938            }
 9939        }
 9940
 9941        false
 9942    }
 9943
 9944    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 9945        self.transact(window, cx, |this, window, cx| {
 9946            this.select_all(&SelectAll, window, cx);
 9947            this.insert("", window, cx);
 9948        });
 9949    }
 9950
 9951    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
 9952        if self.read_only(cx) {
 9953            return;
 9954        }
 9955        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9956        self.transact(window, cx, |this, window, cx| {
 9957            this.select_autoclose_pair(window, cx);
 9958
 9959            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 9960
 9961            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
 9962            if !this.linked_edit_ranges.is_empty() {
 9963                let selections = this.selections.all::<MultiBufferPoint>(&display_map);
 9964                let snapshot = this.buffer.read(cx).snapshot(cx);
 9965
 9966                for selection in selections.iter() {
 9967                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
 9968                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
 9969                    if selection_start.buffer_id != selection_end.buffer_id {
 9970                        continue;
 9971                    }
 9972                    if let Some(ranges) =
 9973                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
 9974                    {
 9975                        for (buffer, entries) in ranges {
 9976                            linked_ranges.entry(buffer).or_default().extend(entries);
 9977                        }
 9978                    }
 9979                }
 9980            }
 9981
 9982            let mut selections = this.selections.all::<MultiBufferPoint>(&display_map);
 9983            for selection in &mut selections {
 9984                if selection.is_empty() {
 9985                    let old_head = selection.head();
 9986                    let mut new_head =
 9987                        movement::left(&display_map, old_head.to_display_point(&display_map))
 9988                            .to_point(&display_map);
 9989                    if let Some((buffer, line_buffer_range)) = display_map
 9990                        .buffer_snapshot()
 9991                        .buffer_line_for_row(MultiBufferRow(old_head.row))
 9992                    {
 9993                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
 9994                        let indent_len = match indent_size.kind {
 9995                            IndentKind::Space => {
 9996                                buffer.settings_at(line_buffer_range.start, cx).tab_size
 9997                            }
 9998                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
 9999                        };
10000                        if old_head.column <= indent_size.len && old_head.column > 0 {
10001                            let indent_len = indent_len.get();
10002                            new_head = cmp::min(
10003                                new_head,
10004                                MultiBufferPoint::new(
10005                                    old_head.row,
10006                                    ((old_head.column - 1) / indent_len) * indent_len,
10007                                ),
10008                            );
10009                        }
10010                    }
10011
10012                    selection.set_head(new_head, SelectionGoal::None);
10013                }
10014            }
10015
10016            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10017            this.insert("", window, cx);
10018            let empty_str: Arc<str> = Arc::from("");
10019            for (buffer, edits) in linked_ranges {
10020                let snapshot = buffer.read(cx).snapshot();
10021                use text::ToPoint as TP;
10022
10023                let edits = edits
10024                    .into_iter()
10025                    .map(|range| {
10026                        let end_point = TP::to_point(&range.end, &snapshot);
10027                        let mut start_point = TP::to_point(&range.start, &snapshot);
10028
10029                        if end_point == start_point {
10030                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
10031                                .saturating_sub(1);
10032                            start_point =
10033                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
10034                        };
10035
10036                        (start_point..end_point, empty_str.clone())
10037                    })
10038                    .sorted_by_key(|(range, _)| range.start)
10039                    .collect::<Vec<_>>();
10040                buffer.update(cx, |this, cx| {
10041                    this.edit(edits, None, cx);
10042                })
10043            }
10044            this.refresh_edit_prediction(true, false, window, cx);
10045            refresh_linked_ranges(this, window, cx);
10046        });
10047    }
10048
10049    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
10050        if self.read_only(cx) {
10051            return;
10052        }
10053        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10054        self.transact(window, cx, |this, window, cx| {
10055            this.change_selections(Default::default(), window, cx, |s| {
10056                s.move_with(|map, selection| {
10057                    if selection.is_empty() {
10058                        let cursor = movement::right(map, selection.head());
10059                        selection.end = cursor;
10060                        selection.reversed = true;
10061                        selection.goal = SelectionGoal::None;
10062                    }
10063                })
10064            });
10065            this.insert("", window, cx);
10066            this.refresh_edit_prediction(true, false, window, cx);
10067        });
10068    }
10069
10070    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
10071        if self.mode.is_single_line() {
10072            cx.propagate();
10073            return;
10074        }
10075
10076        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10077        if self.move_to_prev_snippet_tabstop(window, cx) {
10078            return;
10079        }
10080        self.outdent(&Outdent, window, cx);
10081    }
10082
10083    pub fn next_snippet_tabstop(
10084        &mut self,
10085        _: &NextSnippetTabstop,
10086        window: &mut Window,
10087        cx: &mut Context<Self>,
10088    ) {
10089        if self.mode.is_single_line() || self.snippet_stack.is_empty() {
10090            cx.propagate();
10091            return;
10092        }
10093
10094        if self.move_to_next_snippet_tabstop(window, cx) {
10095            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10096            return;
10097        }
10098        cx.propagate();
10099    }
10100
10101    pub fn previous_snippet_tabstop(
10102        &mut self,
10103        _: &PreviousSnippetTabstop,
10104        window: &mut Window,
10105        cx: &mut Context<Self>,
10106    ) {
10107        if self.mode.is_single_line() || self.snippet_stack.is_empty() {
10108            cx.propagate();
10109            return;
10110        }
10111
10112        if self.move_to_prev_snippet_tabstop(window, cx) {
10113            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10114            return;
10115        }
10116        cx.propagate();
10117    }
10118
10119    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
10120        if self.mode.is_single_line() {
10121            cx.propagate();
10122            return;
10123        }
10124
10125        if self.move_to_next_snippet_tabstop(window, cx) {
10126            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10127            return;
10128        }
10129        if self.read_only(cx) {
10130            return;
10131        }
10132        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10133        let mut selections = self.selections.all_adjusted(&self.display_snapshot(cx));
10134        let buffer = self.buffer.read(cx);
10135        let snapshot = buffer.snapshot(cx);
10136        let rows_iter = selections.iter().map(|s| s.head().row);
10137        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
10138
10139        let has_some_cursor_in_whitespace = selections
10140            .iter()
10141            .filter(|selection| selection.is_empty())
10142            .any(|selection| {
10143                let cursor = selection.head();
10144                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10145                cursor.column < current_indent.len
10146            });
10147
10148        let mut edits = Vec::new();
10149        let mut prev_edited_row = 0;
10150        let mut row_delta = 0;
10151        for selection in &mut selections {
10152            if selection.start.row != prev_edited_row {
10153                row_delta = 0;
10154            }
10155            prev_edited_row = selection.end.row;
10156
10157            // If the selection is non-empty, then increase the indentation of the selected lines.
10158            if !selection.is_empty() {
10159                row_delta =
10160                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10161                continue;
10162            }
10163
10164            let cursor = selection.head();
10165            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10166            if let Some(suggested_indent) =
10167                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
10168            {
10169                // Don't do anything if already at suggested indent
10170                // and there is any other cursor which is not
10171                if has_some_cursor_in_whitespace
10172                    && cursor.column == current_indent.len
10173                    && current_indent.len == suggested_indent.len
10174                {
10175                    continue;
10176                }
10177
10178                // Adjust line and move cursor to suggested indent
10179                // if cursor is not at suggested indent
10180                if cursor.column < suggested_indent.len
10181                    && cursor.column <= current_indent.len
10182                    && current_indent.len <= suggested_indent.len
10183                {
10184                    selection.start = Point::new(cursor.row, suggested_indent.len);
10185                    selection.end = selection.start;
10186                    if row_delta == 0 {
10187                        edits.extend(Buffer::edit_for_indent_size_adjustment(
10188                            cursor.row,
10189                            current_indent,
10190                            suggested_indent,
10191                        ));
10192                        row_delta = suggested_indent.len - current_indent.len;
10193                    }
10194                    continue;
10195                }
10196
10197                // If current indent is more than suggested indent
10198                // only move cursor to current indent and skip indent
10199                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
10200                    selection.start = Point::new(cursor.row, current_indent.len);
10201                    selection.end = selection.start;
10202                    continue;
10203                }
10204            }
10205
10206            // Otherwise, insert a hard or soft tab.
10207            let settings = buffer.language_settings_at(cursor, cx);
10208            let tab_size = if settings.hard_tabs {
10209                IndentSize::tab()
10210            } else {
10211                let tab_size = settings.tab_size.get();
10212                let indent_remainder = snapshot
10213                    .text_for_range(Point::new(cursor.row, 0)..cursor)
10214                    .flat_map(str::chars)
10215                    .fold(row_delta % tab_size, |counter: u32, c| {
10216                        if c == '\t' {
10217                            0
10218                        } else {
10219                            (counter + 1) % tab_size
10220                        }
10221                    });
10222
10223                let chars_to_next_tab_stop = tab_size - indent_remainder;
10224                IndentSize::spaces(chars_to_next_tab_stop)
10225            };
10226            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
10227            selection.end = selection.start;
10228            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
10229            row_delta += tab_size.len;
10230        }
10231
10232        self.transact(window, cx, |this, window, cx| {
10233            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10234            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10235            this.refresh_edit_prediction(true, false, window, cx);
10236        });
10237    }
10238
10239    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
10240        if self.read_only(cx) {
10241            return;
10242        }
10243        if self.mode.is_single_line() {
10244            cx.propagate();
10245            return;
10246        }
10247
10248        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10249        let mut selections = self.selections.all::<Point>(&self.display_snapshot(cx));
10250        let mut prev_edited_row = 0;
10251        let mut row_delta = 0;
10252        let mut edits = Vec::new();
10253        let buffer = self.buffer.read(cx);
10254        let snapshot = buffer.snapshot(cx);
10255        for selection in &mut selections {
10256            if selection.start.row != prev_edited_row {
10257                row_delta = 0;
10258            }
10259            prev_edited_row = selection.end.row;
10260
10261            row_delta =
10262                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10263        }
10264
10265        self.transact(window, cx, |this, window, cx| {
10266            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10267            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10268        });
10269    }
10270
10271    fn indent_selection(
10272        buffer: &MultiBuffer,
10273        snapshot: &MultiBufferSnapshot,
10274        selection: &mut Selection<Point>,
10275        edits: &mut Vec<(Range<Point>, String)>,
10276        delta_for_start_row: u32,
10277        cx: &App,
10278    ) -> u32 {
10279        let settings = buffer.language_settings_at(selection.start, cx);
10280        let tab_size = settings.tab_size.get();
10281        let indent_kind = if settings.hard_tabs {
10282            IndentKind::Tab
10283        } else {
10284            IndentKind::Space
10285        };
10286        let mut start_row = selection.start.row;
10287        let mut end_row = selection.end.row + 1;
10288
10289        // If a selection ends at the beginning of a line, don't indent
10290        // that last line.
10291        if selection.end.column == 0 && selection.end.row > selection.start.row {
10292            end_row -= 1;
10293        }
10294
10295        // Avoid re-indenting a row that has already been indented by a
10296        // previous selection, but still update this selection's column
10297        // to reflect that indentation.
10298        if delta_for_start_row > 0 {
10299            start_row += 1;
10300            selection.start.column += delta_for_start_row;
10301            if selection.end.row == selection.start.row {
10302                selection.end.column += delta_for_start_row;
10303            }
10304        }
10305
10306        let mut delta_for_end_row = 0;
10307        let has_multiple_rows = start_row + 1 != end_row;
10308        for row in start_row..end_row {
10309            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
10310            let indent_delta = match (current_indent.kind, indent_kind) {
10311                (IndentKind::Space, IndentKind::Space) => {
10312                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
10313                    IndentSize::spaces(columns_to_next_tab_stop)
10314                }
10315                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
10316                (_, IndentKind::Tab) => IndentSize::tab(),
10317            };
10318
10319            let start = if has_multiple_rows || current_indent.len < selection.start.column {
10320                0
10321            } else {
10322                selection.start.column
10323            };
10324            let row_start = Point::new(row, start);
10325            edits.push((
10326                row_start..row_start,
10327                indent_delta.chars().collect::<String>(),
10328            ));
10329
10330            // Update this selection's endpoints to reflect the indentation.
10331            if row == selection.start.row {
10332                selection.start.column += indent_delta.len;
10333            }
10334            if row == selection.end.row {
10335                selection.end.column += indent_delta.len;
10336                delta_for_end_row = indent_delta.len;
10337            }
10338        }
10339
10340        if selection.start.row == selection.end.row {
10341            delta_for_start_row + delta_for_end_row
10342        } else {
10343            delta_for_end_row
10344        }
10345    }
10346
10347    pub fn outdent(&mut self, _: &Outdent, 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 display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10358        let selections = self.selections.all::<Point>(&display_map);
10359        let mut deletion_ranges = Vec::new();
10360        let mut last_outdent = None;
10361        {
10362            let buffer = self.buffer.read(cx);
10363            let snapshot = buffer.snapshot(cx);
10364            for selection in &selections {
10365                let settings = buffer.language_settings_at(selection.start, cx);
10366                let tab_size = settings.tab_size.get();
10367                let mut rows = selection.spanned_rows(false, &display_map);
10368
10369                // Avoid re-outdenting a row that has already been outdented by a
10370                // previous selection.
10371                if let Some(last_row) = last_outdent
10372                    && last_row == rows.start
10373                {
10374                    rows.start = rows.start.next_row();
10375                }
10376                let has_multiple_rows = rows.len() > 1;
10377                for row in rows.iter_rows() {
10378                    let indent_size = snapshot.indent_size_for_line(row);
10379                    if indent_size.len > 0 {
10380                        let deletion_len = match indent_size.kind {
10381                            IndentKind::Space => {
10382                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
10383                                if columns_to_prev_tab_stop == 0 {
10384                                    tab_size
10385                                } else {
10386                                    columns_to_prev_tab_stop
10387                                }
10388                            }
10389                            IndentKind::Tab => 1,
10390                        };
10391                        let start = if has_multiple_rows
10392                            || deletion_len > selection.start.column
10393                            || indent_size.len < selection.start.column
10394                        {
10395                            0
10396                        } else {
10397                            selection.start.column - deletion_len
10398                        };
10399                        deletion_ranges.push(
10400                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
10401                        );
10402                        last_outdent = Some(row);
10403                    }
10404                }
10405            }
10406        }
10407
10408        self.transact(window, cx, |this, window, cx| {
10409            this.buffer.update(cx, |buffer, cx| {
10410                let empty_str: Arc<str> = Arc::default();
10411                buffer.edit(
10412                    deletion_ranges
10413                        .into_iter()
10414                        .map(|range| (range, empty_str.clone())),
10415                    None,
10416                    cx,
10417                );
10418            });
10419            let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
10420            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10421        });
10422    }
10423
10424    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
10425        if self.read_only(cx) {
10426            return;
10427        }
10428        if self.mode.is_single_line() {
10429            cx.propagate();
10430            return;
10431        }
10432
10433        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10434        let selections = self
10435            .selections
10436            .all::<usize>(&self.display_snapshot(cx))
10437            .into_iter()
10438            .map(|s| s.range());
10439
10440        self.transact(window, cx, |this, window, cx| {
10441            this.buffer.update(cx, |buffer, cx| {
10442                buffer.autoindent_ranges(selections, cx);
10443            });
10444            let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
10445            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10446        });
10447    }
10448
10449    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
10450        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10451        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10452        let selections = self.selections.all::<Point>(&display_map);
10453
10454        let mut new_cursors = Vec::new();
10455        let mut edit_ranges = Vec::new();
10456        let mut selections = selections.iter().peekable();
10457        while let Some(selection) = selections.next() {
10458            let mut rows = selection.spanned_rows(false, &display_map);
10459
10460            // Accumulate contiguous regions of rows that we want to delete.
10461            while let Some(next_selection) = selections.peek() {
10462                let next_rows = next_selection.spanned_rows(false, &display_map);
10463                if next_rows.start <= rows.end {
10464                    rows.end = next_rows.end;
10465                    selections.next().unwrap();
10466                } else {
10467                    break;
10468                }
10469            }
10470
10471            let buffer = display_map.buffer_snapshot();
10472            let mut edit_start = ToOffset::to_offset(&Point::new(rows.start.0, 0), buffer);
10473            let (edit_end, target_row) = if buffer.max_point().row >= rows.end.0 {
10474                // If there's a line after the range, delete the \n from the end of the row range
10475                (
10476                    ToOffset::to_offset(&Point::new(rows.end.0, 0), buffer),
10477                    rows.end,
10478                )
10479            } else {
10480                // If there isn't a line after the range, delete the \n from the line before the
10481                // start of the row range
10482                edit_start = edit_start.saturating_sub(1);
10483                (buffer.len(), rows.start.previous_row())
10484            };
10485
10486            let text_layout_details = self.text_layout_details(window);
10487            let x = display_map.x_for_display_point(
10488                selection.head().to_display_point(&display_map),
10489                &text_layout_details,
10490            );
10491            let row = Point::new(target_row.0, 0)
10492                .to_display_point(&display_map)
10493                .row();
10494            let column = display_map.display_column_for_x(row, x, &text_layout_details);
10495
10496            new_cursors.push((
10497                selection.id,
10498                buffer.anchor_after(DisplayPoint::new(row, column).to_point(&display_map)),
10499                SelectionGoal::None,
10500            ));
10501            edit_ranges.push(edit_start..edit_end);
10502        }
10503
10504        self.transact(window, cx, |this, window, cx| {
10505            let buffer = this.buffer.update(cx, |buffer, cx| {
10506                let empty_str: Arc<str> = Arc::default();
10507                buffer.edit(
10508                    edit_ranges
10509                        .into_iter()
10510                        .map(|range| (range, empty_str.clone())),
10511                    None,
10512                    cx,
10513                );
10514                buffer.snapshot(cx)
10515            });
10516            let new_selections = new_cursors
10517                .into_iter()
10518                .map(|(id, cursor, goal)| {
10519                    let cursor = cursor.to_point(&buffer);
10520                    Selection {
10521                        id,
10522                        start: cursor,
10523                        end: cursor,
10524                        reversed: false,
10525                        goal,
10526                    }
10527                })
10528                .collect();
10529
10530            this.change_selections(Default::default(), window, cx, |s| {
10531                s.select(new_selections);
10532            });
10533        });
10534    }
10535
10536    pub fn join_lines_impl(
10537        &mut self,
10538        insert_whitespace: bool,
10539        window: &mut Window,
10540        cx: &mut Context<Self>,
10541    ) {
10542        if self.read_only(cx) {
10543            return;
10544        }
10545        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
10546        for selection in self.selections.all::<Point>(&self.display_snapshot(cx)) {
10547            let start = MultiBufferRow(selection.start.row);
10548            // Treat single line selections as if they include the next line. Otherwise this action
10549            // would do nothing for single line selections individual cursors.
10550            let end = if selection.start.row == selection.end.row {
10551                MultiBufferRow(selection.start.row + 1)
10552            } else {
10553                MultiBufferRow(selection.end.row)
10554            };
10555
10556            if let Some(last_row_range) = row_ranges.last_mut()
10557                && start <= last_row_range.end
10558            {
10559                last_row_range.end = end;
10560                continue;
10561            }
10562            row_ranges.push(start..end);
10563        }
10564
10565        let snapshot = self.buffer.read(cx).snapshot(cx);
10566        let mut cursor_positions = Vec::new();
10567        for row_range in &row_ranges {
10568            let anchor = snapshot.anchor_before(Point::new(
10569                row_range.end.previous_row().0,
10570                snapshot.line_len(row_range.end.previous_row()),
10571            ));
10572            cursor_positions.push(anchor..anchor);
10573        }
10574
10575        self.transact(window, cx, |this, window, cx| {
10576            for row_range in row_ranges.into_iter().rev() {
10577                for row in row_range.iter_rows().rev() {
10578                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
10579                    let next_line_row = row.next_row();
10580                    let indent = snapshot.indent_size_for_line(next_line_row);
10581                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
10582
10583                    let replace =
10584                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
10585                            " "
10586                        } else {
10587                            ""
10588                        };
10589
10590                    this.buffer.update(cx, |buffer, cx| {
10591                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
10592                    });
10593                }
10594            }
10595
10596            this.change_selections(Default::default(), window, cx, |s| {
10597                s.select_anchor_ranges(cursor_positions)
10598            });
10599        });
10600    }
10601
10602    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
10603        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10604        self.join_lines_impl(true, window, cx);
10605    }
10606
10607    pub fn sort_lines_case_sensitive(
10608        &mut self,
10609        _: &SortLinesCaseSensitive,
10610        window: &mut Window,
10611        cx: &mut Context<Self>,
10612    ) {
10613        self.manipulate_immutable_lines(window, cx, |lines| lines.sort())
10614    }
10615
10616    pub fn sort_lines_by_length(
10617        &mut self,
10618        _: &SortLinesByLength,
10619        window: &mut Window,
10620        cx: &mut Context<Self>,
10621    ) {
10622        self.manipulate_immutable_lines(window, cx, |lines| {
10623            lines.sort_by_key(|&line| line.chars().count())
10624        })
10625    }
10626
10627    pub fn sort_lines_case_insensitive(
10628        &mut self,
10629        _: &SortLinesCaseInsensitive,
10630        window: &mut Window,
10631        cx: &mut Context<Self>,
10632    ) {
10633        self.manipulate_immutable_lines(window, cx, |lines| {
10634            lines.sort_by_key(|line| line.to_lowercase())
10635        })
10636    }
10637
10638    pub fn unique_lines_case_insensitive(
10639        &mut self,
10640        _: &UniqueLinesCaseInsensitive,
10641        window: &mut Window,
10642        cx: &mut Context<Self>,
10643    ) {
10644        self.manipulate_immutable_lines(window, cx, |lines| {
10645            let mut seen = HashSet::default();
10646            lines.retain(|line| seen.insert(line.to_lowercase()));
10647        })
10648    }
10649
10650    pub fn unique_lines_case_sensitive(
10651        &mut self,
10652        _: &UniqueLinesCaseSensitive,
10653        window: &mut Window,
10654        cx: &mut Context<Self>,
10655    ) {
10656        self.manipulate_immutable_lines(window, cx, |lines| {
10657            let mut seen = HashSet::default();
10658            lines.retain(|line| seen.insert(*line));
10659        })
10660    }
10661
10662    fn enable_wrap_selections_in_tag(&self, cx: &App) -> bool {
10663        let snapshot = self.buffer.read(cx).snapshot(cx);
10664        for selection in self.selections.disjoint_anchors_arc().iter() {
10665            if snapshot
10666                .language_at(selection.start)
10667                .and_then(|lang| lang.config().wrap_characters.as_ref())
10668                .is_some()
10669            {
10670                return true;
10671            }
10672        }
10673        false
10674    }
10675
10676    fn wrap_selections_in_tag(
10677        &mut self,
10678        _: &WrapSelectionsInTag,
10679        window: &mut Window,
10680        cx: &mut Context<Self>,
10681    ) {
10682        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10683
10684        let snapshot = self.buffer.read(cx).snapshot(cx);
10685
10686        let mut edits = Vec::new();
10687        let mut boundaries = Vec::new();
10688
10689        for selection in self
10690            .selections
10691            .all_adjusted(&self.display_snapshot(cx))
10692            .iter()
10693        {
10694            let Some(wrap_config) = snapshot
10695                .language_at(selection.start)
10696                .and_then(|lang| lang.config().wrap_characters.clone())
10697            else {
10698                continue;
10699            };
10700
10701            let open_tag = format!("{}{}", wrap_config.start_prefix, wrap_config.start_suffix);
10702            let close_tag = format!("{}{}", wrap_config.end_prefix, wrap_config.end_suffix);
10703
10704            let start_before = snapshot.anchor_before(selection.start);
10705            let end_after = snapshot.anchor_after(selection.end);
10706
10707            edits.push((start_before..start_before, open_tag));
10708            edits.push((end_after..end_after, close_tag));
10709
10710            boundaries.push((
10711                start_before,
10712                end_after,
10713                wrap_config.start_prefix.len(),
10714                wrap_config.end_suffix.len(),
10715            ));
10716        }
10717
10718        if edits.is_empty() {
10719            return;
10720        }
10721
10722        self.transact(window, cx, |this, window, cx| {
10723            let buffer = this.buffer.update(cx, |buffer, cx| {
10724                buffer.edit(edits, None, cx);
10725                buffer.snapshot(cx)
10726            });
10727
10728            let mut new_selections = Vec::with_capacity(boundaries.len() * 2);
10729            for (start_before, end_after, start_prefix_len, end_suffix_len) in
10730                boundaries.into_iter()
10731            {
10732                let open_offset = start_before.to_offset(&buffer) + start_prefix_len;
10733                let close_offset = end_after.to_offset(&buffer).saturating_sub(end_suffix_len);
10734                new_selections.push(open_offset..open_offset);
10735                new_selections.push(close_offset..close_offset);
10736            }
10737
10738            this.change_selections(Default::default(), window, cx, |s| {
10739                s.select_ranges(new_selections);
10740            });
10741
10742            this.request_autoscroll(Autoscroll::fit(), cx);
10743        });
10744    }
10745
10746    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
10747        let Some(project) = self.project.clone() else {
10748            return;
10749        };
10750        self.reload(project, window, cx)
10751            .detach_and_notify_err(window, cx);
10752    }
10753
10754    pub fn restore_file(
10755        &mut self,
10756        _: &::git::RestoreFile,
10757        window: &mut Window,
10758        cx: &mut Context<Self>,
10759    ) {
10760        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10761        let mut buffer_ids = HashSet::default();
10762        let snapshot = self.buffer().read(cx).snapshot(cx);
10763        for selection in self.selections.all::<usize>(&self.display_snapshot(cx)) {
10764            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
10765        }
10766
10767        let buffer = self.buffer().read(cx);
10768        let ranges = buffer_ids
10769            .into_iter()
10770            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
10771            .collect::<Vec<_>>();
10772
10773        self.restore_hunks_in_ranges(ranges, window, cx);
10774    }
10775
10776    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
10777        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10778        let selections = self
10779            .selections
10780            .all(&self.display_snapshot(cx))
10781            .into_iter()
10782            .map(|s| s.range())
10783            .collect();
10784        self.restore_hunks_in_ranges(selections, window, cx);
10785    }
10786
10787    pub fn restore_hunks_in_ranges(
10788        &mut self,
10789        ranges: Vec<Range<Point>>,
10790        window: &mut Window,
10791        cx: &mut Context<Editor>,
10792    ) {
10793        let mut revert_changes = HashMap::default();
10794        let chunk_by = self
10795            .snapshot(window, cx)
10796            .hunks_for_ranges(ranges)
10797            .into_iter()
10798            .chunk_by(|hunk| hunk.buffer_id);
10799        for (buffer_id, hunks) in &chunk_by {
10800            let hunks = hunks.collect::<Vec<_>>();
10801            for hunk in &hunks {
10802                self.prepare_restore_change(&mut revert_changes, hunk, cx);
10803            }
10804            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
10805        }
10806        drop(chunk_by);
10807        if !revert_changes.is_empty() {
10808            self.transact(window, cx, |editor, window, cx| {
10809                editor.restore(revert_changes, window, cx);
10810            });
10811        }
10812    }
10813
10814    pub fn status_for_buffer_id(&self, buffer_id: BufferId, cx: &App) -> Option<FileStatus> {
10815        if let Some(status) = self
10816            .addons
10817            .iter()
10818            .find_map(|(_, addon)| addon.override_status_for_buffer_id(buffer_id, cx))
10819        {
10820            return Some(status);
10821        }
10822        self.project
10823            .as_ref()?
10824            .read(cx)
10825            .status_for_buffer_id(buffer_id, cx)
10826    }
10827
10828    pub fn open_active_item_in_terminal(
10829        &mut self,
10830        _: &OpenInTerminal,
10831        window: &mut Window,
10832        cx: &mut Context<Self>,
10833    ) {
10834        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
10835            let project_path = buffer.read(cx).project_path(cx)?;
10836            let project = self.project()?.read(cx);
10837            let entry = project.entry_for_path(&project_path, cx)?;
10838            let parent = match &entry.canonical_path {
10839                Some(canonical_path) => canonical_path.to_path_buf(),
10840                None => project.absolute_path(&project_path, cx)?,
10841            }
10842            .parent()?
10843            .to_path_buf();
10844            Some(parent)
10845        }) {
10846            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
10847        }
10848    }
10849
10850    fn set_breakpoint_context_menu(
10851        &mut self,
10852        display_row: DisplayRow,
10853        position: Option<Anchor>,
10854        clicked_point: gpui::Point<Pixels>,
10855        window: &mut Window,
10856        cx: &mut Context<Self>,
10857    ) {
10858        let source = self
10859            .buffer
10860            .read(cx)
10861            .snapshot(cx)
10862            .anchor_before(Point::new(display_row.0, 0u32));
10863
10864        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
10865
10866        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
10867            self,
10868            source,
10869            clicked_point,
10870            context_menu,
10871            window,
10872            cx,
10873        );
10874    }
10875
10876    fn add_edit_breakpoint_block(
10877        &mut self,
10878        anchor: Anchor,
10879        breakpoint: &Breakpoint,
10880        edit_action: BreakpointPromptEditAction,
10881        window: &mut Window,
10882        cx: &mut Context<Self>,
10883    ) {
10884        let weak_editor = cx.weak_entity();
10885        let bp_prompt = cx.new(|cx| {
10886            BreakpointPromptEditor::new(
10887                weak_editor,
10888                anchor,
10889                breakpoint.clone(),
10890                edit_action,
10891                window,
10892                cx,
10893            )
10894        });
10895
10896        let height = bp_prompt.update(cx, |this, cx| {
10897            this.prompt
10898                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
10899        });
10900        let cloned_prompt = bp_prompt.clone();
10901        let blocks = vec![BlockProperties {
10902            style: BlockStyle::Sticky,
10903            placement: BlockPlacement::Above(anchor),
10904            height: Some(height),
10905            render: Arc::new(move |cx| {
10906                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
10907                cloned_prompt.clone().into_any_element()
10908            }),
10909            priority: 0,
10910        }];
10911
10912        let focus_handle = bp_prompt.focus_handle(cx);
10913        window.focus(&focus_handle);
10914
10915        let block_ids = self.insert_blocks(blocks, None, cx);
10916        bp_prompt.update(cx, |prompt, _| {
10917            prompt.add_block_ids(block_ids);
10918        });
10919    }
10920
10921    pub(crate) fn breakpoint_at_row(
10922        &self,
10923        row: u32,
10924        window: &mut Window,
10925        cx: &mut Context<Self>,
10926    ) -> Option<(Anchor, Breakpoint)> {
10927        let snapshot = self.snapshot(window, cx);
10928        let breakpoint_position = snapshot.buffer_snapshot().anchor_before(Point::new(row, 0));
10929
10930        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10931    }
10932
10933    pub(crate) fn breakpoint_at_anchor(
10934        &self,
10935        breakpoint_position: Anchor,
10936        snapshot: &EditorSnapshot,
10937        cx: &mut Context<Self>,
10938    ) -> Option<(Anchor, Breakpoint)> {
10939        let buffer = self
10940            .buffer
10941            .read(cx)
10942            .buffer_for_anchor(breakpoint_position, cx)?;
10943
10944        let enclosing_excerpt = breakpoint_position.excerpt_id;
10945        let buffer_snapshot = buffer.read(cx).snapshot();
10946
10947        let row = buffer_snapshot
10948            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
10949            .row;
10950
10951        let line_len = snapshot.buffer_snapshot().line_len(MultiBufferRow(row));
10952        let anchor_end = snapshot
10953            .buffer_snapshot()
10954            .anchor_after(Point::new(row, line_len));
10955
10956        self.breakpoint_store
10957            .as_ref()?
10958            .read_with(cx, |breakpoint_store, cx| {
10959                breakpoint_store
10960                    .breakpoints(
10961                        &buffer,
10962                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
10963                        &buffer_snapshot,
10964                        cx,
10965                    )
10966                    .next()
10967                    .and_then(|(bp, _)| {
10968                        let breakpoint_row = buffer_snapshot
10969                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
10970                            .row;
10971
10972                        if breakpoint_row == row {
10973                            snapshot
10974                                .buffer_snapshot()
10975                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
10976                                .map(|position| (position, bp.bp.clone()))
10977                        } else {
10978                            None
10979                        }
10980                    })
10981            })
10982    }
10983
10984    pub fn edit_log_breakpoint(
10985        &mut self,
10986        _: &EditLogBreakpoint,
10987        window: &mut Window,
10988        cx: &mut Context<Self>,
10989    ) {
10990        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10991            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
10992                message: None,
10993                state: BreakpointState::Enabled,
10994                condition: None,
10995                hit_condition: None,
10996            });
10997
10998            self.add_edit_breakpoint_block(
10999                anchor,
11000                &breakpoint,
11001                BreakpointPromptEditAction::Log,
11002                window,
11003                cx,
11004            );
11005        }
11006    }
11007
11008    fn breakpoints_at_cursors(
11009        &self,
11010        window: &mut Window,
11011        cx: &mut Context<Self>,
11012    ) -> Vec<(Anchor, Option<Breakpoint>)> {
11013        let snapshot = self.snapshot(window, cx);
11014        let cursors = self
11015            .selections
11016            .disjoint_anchors_arc()
11017            .iter()
11018            .map(|selection| {
11019                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot());
11020
11021                let breakpoint_position = self
11022                    .breakpoint_at_row(cursor_position.row, window, cx)
11023                    .map(|bp| bp.0)
11024                    .unwrap_or_else(|| {
11025                        snapshot
11026                            .display_snapshot
11027                            .buffer_snapshot()
11028                            .anchor_after(Point::new(cursor_position.row, 0))
11029                    });
11030
11031                let breakpoint = self
11032                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
11033                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
11034
11035                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
11036            })
11037            // 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.
11038            .collect::<HashMap<Anchor, _>>();
11039
11040        cursors.into_iter().collect()
11041    }
11042
11043    pub fn enable_breakpoint(
11044        &mut self,
11045        _: &crate::actions::EnableBreakpoint,
11046        window: &mut Window,
11047        cx: &mut Context<Self>,
11048    ) {
11049        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11050            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
11051                continue;
11052            };
11053            self.edit_breakpoint_at_anchor(
11054                anchor,
11055                breakpoint,
11056                BreakpointEditAction::InvertState,
11057                cx,
11058            );
11059        }
11060    }
11061
11062    pub fn disable_breakpoint(
11063        &mut self,
11064        _: &crate::actions::DisableBreakpoint,
11065        window: &mut Window,
11066        cx: &mut Context<Self>,
11067    ) {
11068        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11069            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
11070                continue;
11071            };
11072            self.edit_breakpoint_at_anchor(
11073                anchor,
11074                breakpoint,
11075                BreakpointEditAction::InvertState,
11076                cx,
11077            );
11078        }
11079    }
11080
11081    pub fn toggle_breakpoint(
11082        &mut self,
11083        _: &crate::actions::ToggleBreakpoint,
11084        window: &mut Window,
11085        cx: &mut Context<Self>,
11086    ) {
11087        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11088            if let Some(breakpoint) = breakpoint {
11089                self.edit_breakpoint_at_anchor(
11090                    anchor,
11091                    breakpoint,
11092                    BreakpointEditAction::Toggle,
11093                    cx,
11094                );
11095            } else {
11096                self.edit_breakpoint_at_anchor(
11097                    anchor,
11098                    Breakpoint::new_standard(),
11099                    BreakpointEditAction::Toggle,
11100                    cx,
11101                );
11102            }
11103        }
11104    }
11105
11106    pub fn edit_breakpoint_at_anchor(
11107        &mut self,
11108        breakpoint_position: Anchor,
11109        breakpoint: Breakpoint,
11110        edit_action: BreakpointEditAction,
11111        cx: &mut Context<Self>,
11112    ) {
11113        let Some(breakpoint_store) = &self.breakpoint_store else {
11114            return;
11115        };
11116
11117        let Some(buffer) = self
11118            .buffer
11119            .read(cx)
11120            .buffer_for_anchor(breakpoint_position, cx)
11121        else {
11122            return;
11123        };
11124
11125        breakpoint_store.update(cx, |breakpoint_store, cx| {
11126            breakpoint_store.toggle_breakpoint(
11127                buffer,
11128                BreakpointWithPosition {
11129                    position: breakpoint_position.text_anchor,
11130                    bp: breakpoint,
11131                },
11132                edit_action,
11133                cx,
11134            );
11135        });
11136
11137        cx.notify();
11138    }
11139
11140    #[cfg(any(test, feature = "test-support"))]
11141    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
11142        self.breakpoint_store.clone()
11143    }
11144
11145    pub fn prepare_restore_change(
11146        &self,
11147        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
11148        hunk: &MultiBufferDiffHunk,
11149        cx: &mut App,
11150    ) -> Option<()> {
11151        if hunk.is_created_file() {
11152            return None;
11153        }
11154        let buffer = self.buffer.read(cx);
11155        let diff = buffer.diff_for(hunk.buffer_id)?;
11156        let buffer = buffer.buffer(hunk.buffer_id)?;
11157        let buffer = buffer.read(cx);
11158        let original_text = diff
11159            .read(cx)
11160            .base_text()
11161            .as_rope()
11162            .slice(hunk.diff_base_byte_range.clone());
11163        let buffer_snapshot = buffer.snapshot();
11164        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
11165        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
11166            probe
11167                .0
11168                .start
11169                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
11170                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
11171        }) {
11172            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
11173            Some(())
11174        } else {
11175            None
11176        }
11177    }
11178
11179    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
11180        self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())
11181    }
11182
11183    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
11184        self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut rand::rng()))
11185    }
11186
11187    fn manipulate_lines<M>(
11188        &mut self,
11189        window: &mut Window,
11190        cx: &mut Context<Self>,
11191        mut manipulate: M,
11192    ) where
11193        M: FnMut(&str) -> LineManipulationResult,
11194    {
11195        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11196
11197        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11198        let buffer = self.buffer.read(cx).snapshot(cx);
11199
11200        let mut edits = Vec::new();
11201
11202        let selections = self.selections.all::<Point>(&display_map);
11203        let mut selections = selections.iter().peekable();
11204        let mut contiguous_row_selections = Vec::new();
11205        let mut new_selections = Vec::new();
11206        let mut added_lines = 0;
11207        let mut removed_lines = 0;
11208
11209        while let Some(selection) = selections.next() {
11210            let (start_row, end_row) = consume_contiguous_rows(
11211                &mut contiguous_row_selections,
11212                selection,
11213                &display_map,
11214                &mut selections,
11215            );
11216
11217            let start_point = Point::new(start_row.0, 0);
11218            let end_point = Point::new(
11219                end_row.previous_row().0,
11220                buffer.line_len(end_row.previous_row()),
11221            );
11222            let text = buffer
11223                .text_for_range(start_point..end_point)
11224                .collect::<String>();
11225
11226            let LineManipulationResult {
11227                new_text,
11228                line_count_before,
11229                line_count_after,
11230            } = manipulate(&text);
11231
11232            edits.push((start_point..end_point, new_text));
11233
11234            // Selections must change based on added and removed line count
11235            let start_row =
11236                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
11237            let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);
11238            new_selections.push(Selection {
11239                id: selection.id,
11240                start: start_row,
11241                end: end_row,
11242                goal: SelectionGoal::None,
11243                reversed: selection.reversed,
11244            });
11245
11246            if line_count_after > line_count_before {
11247                added_lines += line_count_after - line_count_before;
11248            } else if line_count_before > line_count_after {
11249                removed_lines += line_count_before - line_count_after;
11250            }
11251        }
11252
11253        self.transact(window, cx, |this, window, cx| {
11254            let buffer = this.buffer.update(cx, |buffer, cx| {
11255                buffer.edit(edits, None, cx);
11256                buffer.snapshot(cx)
11257            });
11258
11259            // Recalculate offsets on newly edited buffer
11260            let new_selections = new_selections
11261                .iter()
11262                .map(|s| {
11263                    let start_point = Point::new(s.start.0, 0);
11264                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
11265                    Selection {
11266                        id: s.id,
11267                        start: buffer.point_to_offset(start_point),
11268                        end: buffer.point_to_offset(end_point),
11269                        goal: s.goal,
11270                        reversed: s.reversed,
11271                    }
11272                })
11273                .collect();
11274
11275            this.change_selections(Default::default(), window, cx, |s| {
11276                s.select(new_selections);
11277            });
11278
11279            this.request_autoscroll(Autoscroll::fit(), cx);
11280        });
11281    }
11282
11283    fn manipulate_immutable_lines<Fn>(
11284        &mut self,
11285        window: &mut Window,
11286        cx: &mut Context<Self>,
11287        mut callback: Fn,
11288    ) where
11289        Fn: FnMut(&mut Vec<&str>),
11290    {
11291        self.manipulate_lines(window, cx, |text| {
11292            let mut lines: Vec<&str> = text.split('\n').collect();
11293            let line_count_before = lines.len();
11294
11295            callback(&mut lines);
11296
11297            LineManipulationResult {
11298                new_text: lines.join("\n"),
11299                line_count_before,
11300                line_count_after: lines.len(),
11301            }
11302        });
11303    }
11304
11305    fn manipulate_mutable_lines<Fn>(
11306        &mut self,
11307        window: &mut Window,
11308        cx: &mut Context<Self>,
11309        mut callback: Fn,
11310    ) where
11311        Fn: FnMut(&mut Vec<Cow<'_, str>>),
11312    {
11313        self.manipulate_lines(window, cx, |text| {
11314            let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
11315            let line_count_before = lines.len();
11316
11317            callback(&mut lines);
11318
11319            LineManipulationResult {
11320                new_text: lines.join("\n"),
11321                line_count_before,
11322                line_count_after: lines.len(),
11323            }
11324        });
11325    }
11326
11327    pub fn convert_indentation_to_spaces(
11328        &mut self,
11329        _: &ConvertIndentationToSpaces,
11330        window: &mut Window,
11331        cx: &mut Context<Self>,
11332    ) {
11333        let settings = self.buffer.read(cx).language_settings(cx);
11334        let tab_size = settings.tab_size.get() as usize;
11335
11336        self.manipulate_mutable_lines(window, cx, |lines| {
11337            // Allocates a reasonably sized scratch buffer once for the whole loop
11338            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11339            // Avoids recomputing spaces that could be inserted many times
11340            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11341                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11342                .collect();
11343
11344            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11345                let mut chars = line.as_ref().chars();
11346                let mut col = 0;
11347                let mut changed = false;
11348
11349                for ch in chars.by_ref() {
11350                    match ch {
11351                        ' ' => {
11352                            reindented_line.push(' ');
11353                            col += 1;
11354                        }
11355                        '\t' => {
11356                            // \t are converted to spaces depending on the current column
11357                            let spaces_len = tab_size - (col % tab_size);
11358                            reindented_line.extend(&space_cache[spaces_len - 1]);
11359                            col += spaces_len;
11360                            changed = true;
11361                        }
11362                        _ => {
11363                            // If we dont append before break, the character is consumed
11364                            reindented_line.push(ch);
11365                            break;
11366                        }
11367                    }
11368                }
11369
11370                if !changed {
11371                    reindented_line.clear();
11372                    continue;
11373                }
11374                // Append the rest of the line and replace old reference with new one
11375                reindented_line.extend(chars);
11376                *line = Cow::Owned(reindented_line.clone());
11377                reindented_line.clear();
11378            }
11379        });
11380    }
11381
11382    pub fn convert_indentation_to_tabs(
11383        &mut self,
11384        _: &ConvertIndentationToTabs,
11385        window: &mut Window,
11386        cx: &mut Context<Self>,
11387    ) {
11388        let settings = self.buffer.read(cx).language_settings(cx);
11389        let tab_size = settings.tab_size.get() as usize;
11390
11391        self.manipulate_mutable_lines(window, cx, |lines| {
11392            // Allocates a reasonably sized buffer once for the whole loop
11393            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11394            // Avoids recomputing spaces that could be inserted many times
11395            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11396                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11397                .collect();
11398
11399            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11400                let mut chars = line.chars();
11401                let mut spaces_count = 0;
11402                let mut first_non_indent_char = None;
11403                let mut changed = false;
11404
11405                for ch in chars.by_ref() {
11406                    match ch {
11407                        ' ' => {
11408                            // Keep track of spaces. Append \t when we reach tab_size
11409                            spaces_count += 1;
11410                            changed = true;
11411                            if spaces_count == tab_size {
11412                                reindented_line.push('\t');
11413                                spaces_count = 0;
11414                            }
11415                        }
11416                        '\t' => {
11417                            reindented_line.push('\t');
11418                            spaces_count = 0;
11419                        }
11420                        _ => {
11421                            // Dont append it yet, we might have remaining spaces
11422                            first_non_indent_char = Some(ch);
11423                            break;
11424                        }
11425                    }
11426                }
11427
11428                if !changed {
11429                    reindented_line.clear();
11430                    continue;
11431                }
11432                // Remaining spaces that didn't make a full tab stop
11433                if spaces_count > 0 {
11434                    reindented_line.extend(&space_cache[spaces_count - 1]);
11435                }
11436                // If we consume an extra character that was not indentation, add it back
11437                if let Some(extra_char) = first_non_indent_char {
11438                    reindented_line.push(extra_char);
11439                }
11440                // Append the rest of the line and replace old reference with new one
11441                reindented_line.extend(chars);
11442                *line = Cow::Owned(reindented_line.clone());
11443                reindented_line.clear();
11444            }
11445        });
11446    }
11447
11448    pub fn convert_to_upper_case(
11449        &mut self,
11450        _: &ConvertToUpperCase,
11451        window: &mut Window,
11452        cx: &mut Context<Self>,
11453    ) {
11454        self.manipulate_text(window, cx, |text| text.to_uppercase())
11455    }
11456
11457    pub fn convert_to_lower_case(
11458        &mut self,
11459        _: &ConvertToLowerCase,
11460        window: &mut Window,
11461        cx: &mut Context<Self>,
11462    ) {
11463        self.manipulate_text(window, cx, |text| text.to_lowercase())
11464    }
11465
11466    pub fn convert_to_title_case(
11467        &mut self,
11468        _: &ConvertToTitleCase,
11469        window: &mut Window,
11470        cx: &mut Context<Self>,
11471    ) {
11472        self.manipulate_text(window, cx, |text| {
11473            text.split('\n')
11474                .map(|line| line.to_case(Case::Title))
11475                .join("\n")
11476        })
11477    }
11478
11479    pub fn convert_to_snake_case(
11480        &mut self,
11481        _: &ConvertToSnakeCase,
11482        window: &mut Window,
11483        cx: &mut Context<Self>,
11484    ) {
11485        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
11486    }
11487
11488    pub fn convert_to_kebab_case(
11489        &mut self,
11490        _: &ConvertToKebabCase,
11491        window: &mut Window,
11492        cx: &mut Context<Self>,
11493    ) {
11494        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
11495    }
11496
11497    pub fn convert_to_upper_camel_case(
11498        &mut self,
11499        _: &ConvertToUpperCamelCase,
11500        window: &mut Window,
11501        cx: &mut Context<Self>,
11502    ) {
11503        self.manipulate_text(window, cx, |text| {
11504            text.split('\n')
11505                .map(|line| line.to_case(Case::UpperCamel))
11506                .join("\n")
11507        })
11508    }
11509
11510    pub fn convert_to_lower_camel_case(
11511        &mut self,
11512        _: &ConvertToLowerCamelCase,
11513        window: &mut Window,
11514        cx: &mut Context<Self>,
11515    ) {
11516        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
11517    }
11518
11519    pub fn convert_to_opposite_case(
11520        &mut self,
11521        _: &ConvertToOppositeCase,
11522        window: &mut Window,
11523        cx: &mut Context<Self>,
11524    ) {
11525        self.manipulate_text(window, cx, |text| {
11526            text.chars()
11527                .fold(String::with_capacity(text.len()), |mut t, c| {
11528                    if c.is_uppercase() {
11529                        t.extend(c.to_lowercase());
11530                    } else {
11531                        t.extend(c.to_uppercase());
11532                    }
11533                    t
11534                })
11535        })
11536    }
11537
11538    pub fn convert_to_sentence_case(
11539        &mut self,
11540        _: &ConvertToSentenceCase,
11541        window: &mut Window,
11542        cx: &mut Context<Self>,
11543    ) {
11544        self.manipulate_text(window, cx, |text| text.to_case(Case::Sentence))
11545    }
11546
11547    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
11548        self.manipulate_text(window, cx, |text| {
11549            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
11550            if has_upper_case_characters {
11551                text.to_lowercase()
11552            } else {
11553                text.to_uppercase()
11554            }
11555        })
11556    }
11557
11558    pub fn convert_to_rot13(
11559        &mut self,
11560        _: &ConvertToRot13,
11561        window: &mut Window,
11562        cx: &mut Context<Self>,
11563    ) {
11564        self.manipulate_text(window, cx, |text| {
11565            text.chars()
11566                .map(|c| match c {
11567                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
11568                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
11569                    _ => c,
11570                })
11571                .collect()
11572        })
11573    }
11574
11575    pub fn convert_to_rot47(
11576        &mut self,
11577        _: &ConvertToRot47,
11578        window: &mut Window,
11579        cx: &mut Context<Self>,
11580    ) {
11581        self.manipulate_text(window, cx, |text| {
11582            text.chars()
11583                .map(|c| {
11584                    let code_point = c as u32;
11585                    if code_point >= 33 && code_point <= 126 {
11586                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
11587                    }
11588                    c
11589                })
11590                .collect()
11591        })
11592    }
11593
11594    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
11595    where
11596        Fn: FnMut(&str) -> String,
11597    {
11598        let buffer = self.buffer.read(cx).snapshot(cx);
11599
11600        let mut new_selections = Vec::new();
11601        let mut edits = Vec::new();
11602        let mut selection_adjustment = 0i32;
11603
11604        for selection in self.selections.all_adjusted(&self.display_snapshot(cx)) {
11605            let selection_is_empty = selection.is_empty();
11606
11607            let (start, end) = if selection_is_empty {
11608                let (word_range, _) = buffer.surrounding_word(selection.start, None);
11609                (word_range.start, word_range.end)
11610            } else {
11611                (
11612                    buffer.point_to_offset(selection.start),
11613                    buffer.point_to_offset(selection.end),
11614                )
11615            };
11616
11617            let text = buffer.text_for_range(start..end).collect::<String>();
11618            let old_length = text.len() as i32;
11619            let text = callback(&text);
11620
11621            new_selections.push(Selection {
11622                start: (start as i32 - selection_adjustment) as usize,
11623                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
11624                goal: SelectionGoal::None,
11625                id: selection.id,
11626                reversed: selection.reversed,
11627            });
11628
11629            selection_adjustment += old_length - text.len() as i32;
11630
11631            edits.push((start..end, text));
11632        }
11633
11634        self.transact(window, cx, |this, window, cx| {
11635            this.buffer.update(cx, |buffer, cx| {
11636                buffer.edit(edits, None, cx);
11637            });
11638
11639            this.change_selections(Default::default(), window, cx, |s| {
11640                s.select(new_selections);
11641            });
11642
11643            this.request_autoscroll(Autoscroll::fit(), cx);
11644        });
11645    }
11646
11647    pub fn move_selection_on_drop(
11648        &mut self,
11649        selection: &Selection<Anchor>,
11650        target: DisplayPoint,
11651        is_cut: bool,
11652        window: &mut Window,
11653        cx: &mut Context<Self>,
11654    ) {
11655        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11656        let buffer = display_map.buffer_snapshot();
11657        let mut edits = Vec::new();
11658        let insert_point = display_map
11659            .clip_point(target, Bias::Left)
11660            .to_point(&display_map);
11661        let text = buffer
11662            .text_for_range(selection.start..selection.end)
11663            .collect::<String>();
11664        if is_cut {
11665            edits.push(((selection.start..selection.end), String::new()));
11666        }
11667        let insert_anchor = buffer.anchor_before(insert_point);
11668        edits.push(((insert_anchor..insert_anchor), text));
11669        let last_edit_start = insert_anchor.bias_left(buffer);
11670        let last_edit_end = insert_anchor.bias_right(buffer);
11671        self.transact(window, cx, |this, window, cx| {
11672            this.buffer.update(cx, |buffer, cx| {
11673                buffer.edit(edits, None, cx);
11674            });
11675            this.change_selections(Default::default(), window, cx, |s| {
11676                s.select_anchor_ranges([last_edit_start..last_edit_end]);
11677            });
11678        });
11679    }
11680
11681    pub fn clear_selection_drag_state(&mut self) {
11682        self.selection_drag_state = SelectionDragState::None;
11683    }
11684
11685    pub fn duplicate(
11686        &mut self,
11687        upwards: bool,
11688        whole_lines: bool,
11689        window: &mut Window,
11690        cx: &mut Context<Self>,
11691    ) {
11692        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11693
11694        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11695        let buffer = display_map.buffer_snapshot();
11696        let selections = self.selections.all::<Point>(&display_map);
11697
11698        let mut edits = Vec::new();
11699        let mut selections_iter = selections.iter().peekable();
11700        while let Some(selection) = selections_iter.next() {
11701            let mut rows = selection.spanned_rows(false, &display_map);
11702            // duplicate line-wise
11703            if whole_lines || selection.start == selection.end {
11704                // Avoid duplicating the same lines twice.
11705                while let Some(next_selection) = selections_iter.peek() {
11706                    let next_rows = next_selection.spanned_rows(false, &display_map);
11707                    if next_rows.start < rows.end {
11708                        rows.end = next_rows.end;
11709                        selections_iter.next().unwrap();
11710                    } else {
11711                        break;
11712                    }
11713                }
11714
11715                // Copy the text from the selected row region and splice it either at the start
11716                // or end of the region.
11717                let start = Point::new(rows.start.0, 0);
11718                let end = Point::new(
11719                    rows.end.previous_row().0,
11720                    buffer.line_len(rows.end.previous_row()),
11721                );
11722
11723                let mut text = buffer.text_for_range(start..end).collect::<String>();
11724
11725                let insert_location = if upwards {
11726                    // When duplicating upward, we need to insert before the current line.
11727                    // If we're on the last line and it doesn't end with a newline,
11728                    // we need to add a newline before the duplicated content.
11729                    let needs_leading_newline = rows.end.0 >= buffer.max_point().row
11730                        && buffer.max_point().column > 0
11731                        && !text.ends_with('\n');
11732
11733                    if needs_leading_newline {
11734                        text.insert(0, '\n');
11735                        end
11736                    } else {
11737                        text.push('\n');
11738                        Point::new(rows.start.0, 0)
11739                    }
11740                } else {
11741                    text.push('\n');
11742                    start
11743                };
11744                edits.push((insert_location..insert_location, text));
11745            } else {
11746                // duplicate character-wise
11747                let start = selection.start;
11748                let end = selection.end;
11749                let text = buffer.text_for_range(start..end).collect::<String>();
11750                edits.push((selection.end..selection.end, text));
11751            }
11752        }
11753
11754        self.transact(window, cx, |this, window, cx| {
11755            this.buffer.update(cx, |buffer, cx| {
11756                buffer.edit(edits, None, cx);
11757            });
11758
11759            // When duplicating upward with whole lines, move the cursor to the duplicated line
11760            if upwards && whole_lines {
11761                let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
11762
11763                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
11764                    let mut new_ranges = Vec::new();
11765                    let selections = s.all::<Point>(&display_map);
11766                    let mut selections_iter = selections.iter().peekable();
11767
11768                    while let Some(first_selection) = selections_iter.next() {
11769                        // Group contiguous selections together to find the total row span
11770                        let mut group_selections = vec![first_selection];
11771                        let mut rows = first_selection.spanned_rows(false, &display_map);
11772
11773                        while let Some(next_selection) = selections_iter.peek() {
11774                            let next_rows = next_selection.spanned_rows(false, &display_map);
11775                            if next_rows.start < rows.end {
11776                                rows.end = next_rows.end;
11777                                group_selections.push(selections_iter.next().unwrap());
11778                            } else {
11779                                break;
11780                            }
11781                        }
11782
11783                        let row_count = rows.end.0 - rows.start.0;
11784
11785                        // Move all selections in this group up by the total number of duplicated rows
11786                        for selection in group_selections {
11787                            let new_start = Point::new(
11788                                selection.start.row.saturating_sub(row_count),
11789                                selection.start.column,
11790                            );
11791
11792                            let new_end = Point::new(
11793                                selection.end.row.saturating_sub(row_count),
11794                                selection.end.column,
11795                            );
11796
11797                            new_ranges.push(new_start..new_end);
11798                        }
11799                    }
11800
11801                    s.select_ranges(new_ranges);
11802                });
11803            }
11804
11805            this.request_autoscroll(Autoscroll::fit(), cx);
11806        });
11807    }
11808
11809    pub fn duplicate_line_up(
11810        &mut self,
11811        _: &DuplicateLineUp,
11812        window: &mut Window,
11813        cx: &mut Context<Self>,
11814    ) {
11815        self.duplicate(true, true, window, cx);
11816    }
11817
11818    pub fn duplicate_line_down(
11819        &mut self,
11820        _: &DuplicateLineDown,
11821        window: &mut Window,
11822        cx: &mut Context<Self>,
11823    ) {
11824        self.duplicate(false, true, window, cx);
11825    }
11826
11827    pub fn duplicate_selection(
11828        &mut self,
11829        _: &DuplicateSelection,
11830        window: &mut Window,
11831        cx: &mut Context<Self>,
11832    ) {
11833        self.duplicate(false, false, window, cx);
11834    }
11835
11836    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
11837        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11838        if self.mode.is_single_line() {
11839            cx.propagate();
11840            return;
11841        }
11842
11843        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11844        let buffer = self.buffer.read(cx).snapshot(cx);
11845
11846        let mut edits = Vec::new();
11847        let mut unfold_ranges = Vec::new();
11848        let mut refold_creases = Vec::new();
11849
11850        let selections = self.selections.all::<Point>(&display_map);
11851        let mut selections = selections.iter().peekable();
11852        let mut contiguous_row_selections = Vec::new();
11853        let mut new_selections = Vec::new();
11854
11855        while let Some(selection) = selections.next() {
11856            // Find all the selections that span a contiguous row range
11857            let (start_row, end_row) = consume_contiguous_rows(
11858                &mut contiguous_row_selections,
11859                selection,
11860                &display_map,
11861                &mut selections,
11862            );
11863
11864            // Move the text spanned by the row range to be before the line preceding the row range
11865            if start_row.0 > 0 {
11866                let range_to_move = Point::new(
11867                    start_row.previous_row().0,
11868                    buffer.line_len(start_row.previous_row()),
11869                )
11870                    ..Point::new(
11871                        end_row.previous_row().0,
11872                        buffer.line_len(end_row.previous_row()),
11873                    );
11874                let insertion_point = display_map
11875                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
11876                    .0;
11877
11878                // Don't move lines across excerpts
11879                if buffer
11880                    .excerpt_containing(insertion_point..range_to_move.end)
11881                    .is_some()
11882                {
11883                    let text = buffer
11884                        .text_for_range(range_to_move.clone())
11885                        .flat_map(|s| s.chars())
11886                        .skip(1)
11887                        .chain(['\n'])
11888                        .collect::<String>();
11889
11890                    edits.push((
11891                        buffer.anchor_after(range_to_move.start)
11892                            ..buffer.anchor_before(range_to_move.end),
11893                        String::new(),
11894                    ));
11895                    let insertion_anchor = buffer.anchor_after(insertion_point);
11896                    edits.push((insertion_anchor..insertion_anchor, text));
11897
11898                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
11899
11900                    // Move selections up
11901                    new_selections.extend(contiguous_row_selections.drain(..).map(
11902                        |mut selection| {
11903                            selection.start.row -= row_delta;
11904                            selection.end.row -= row_delta;
11905                            selection
11906                        },
11907                    ));
11908
11909                    // Move folds up
11910                    unfold_ranges.push(range_to_move.clone());
11911                    for fold in display_map.folds_in_range(
11912                        buffer.anchor_before(range_to_move.start)
11913                            ..buffer.anchor_after(range_to_move.end),
11914                    ) {
11915                        let mut start = fold.range.start.to_point(&buffer);
11916                        let mut end = fold.range.end.to_point(&buffer);
11917                        start.row -= row_delta;
11918                        end.row -= row_delta;
11919                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11920                    }
11921                }
11922            }
11923
11924            // If we didn't move line(s), preserve the existing selections
11925            new_selections.append(&mut contiguous_row_selections);
11926        }
11927
11928        self.transact(window, cx, |this, window, cx| {
11929            this.unfold_ranges(&unfold_ranges, true, true, cx);
11930            this.buffer.update(cx, |buffer, cx| {
11931                for (range, text) in edits {
11932                    buffer.edit([(range, text)], None, cx);
11933                }
11934            });
11935            this.fold_creases(refold_creases, true, window, cx);
11936            this.change_selections(Default::default(), window, cx, |s| {
11937                s.select(new_selections);
11938            })
11939        });
11940    }
11941
11942    pub fn move_line_down(
11943        &mut self,
11944        _: &MoveLineDown,
11945        window: &mut Window,
11946        cx: &mut Context<Self>,
11947    ) {
11948        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11949        if self.mode.is_single_line() {
11950            cx.propagate();
11951            return;
11952        }
11953
11954        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11955        let buffer = self.buffer.read(cx).snapshot(cx);
11956
11957        let mut edits = Vec::new();
11958        let mut unfold_ranges = Vec::new();
11959        let mut refold_creases = Vec::new();
11960
11961        let selections = self.selections.all::<Point>(&display_map);
11962        let mut selections = selections.iter().peekable();
11963        let mut contiguous_row_selections = Vec::new();
11964        let mut new_selections = Vec::new();
11965
11966        while let Some(selection) = selections.next() {
11967            // Find all the selections that span a contiguous row range
11968            let (start_row, end_row) = consume_contiguous_rows(
11969                &mut contiguous_row_selections,
11970                selection,
11971                &display_map,
11972                &mut selections,
11973            );
11974
11975            // Move the text spanned by the row range to be after the last line of the row range
11976            if end_row.0 <= buffer.max_point().row {
11977                let range_to_move =
11978                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
11979                let insertion_point = display_map
11980                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
11981                    .0;
11982
11983                // Don't move lines across excerpt boundaries
11984                if buffer
11985                    .excerpt_containing(range_to_move.start..insertion_point)
11986                    .is_some()
11987                {
11988                    let mut text = String::from("\n");
11989                    text.extend(buffer.text_for_range(range_to_move.clone()));
11990                    text.pop(); // Drop trailing newline
11991                    edits.push((
11992                        buffer.anchor_after(range_to_move.start)
11993                            ..buffer.anchor_before(range_to_move.end),
11994                        String::new(),
11995                    ));
11996                    let insertion_anchor = buffer.anchor_after(insertion_point);
11997                    edits.push((insertion_anchor..insertion_anchor, text));
11998
11999                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
12000
12001                    // Move selections down
12002                    new_selections.extend(contiguous_row_selections.drain(..).map(
12003                        |mut selection| {
12004                            selection.start.row += row_delta;
12005                            selection.end.row += row_delta;
12006                            selection
12007                        },
12008                    ));
12009
12010                    // Move folds down
12011                    unfold_ranges.push(range_to_move.clone());
12012                    for fold in display_map.folds_in_range(
12013                        buffer.anchor_before(range_to_move.start)
12014                            ..buffer.anchor_after(range_to_move.end),
12015                    ) {
12016                        let mut start = fold.range.start.to_point(&buffer);
12017                        let mut end = fold.range.end.to_point(&buffer);
12018                        start.row += row_delta;
12019                        end.row += row_delta;
12020                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
12021                    }
12022                }
12023            }
12024
12025            // If we didn't move line(s), preserve the existing selections
12026            new_selections.append(&mut contiguous_row_selections);
12027        }
12028
12029        self.transact(window, cx, |this, window, cx| {
12030            this.unfold_ranges(&unfold_ranges, true, true, cx);
12031            this.buffer.update(cx, |buffer, cx| {
12032                for (range, text) in edits {
12033                    buffer.edit([(range, text)], None, cx);
12034                }
12035            });
12036            this.fold_creases(refold_creases, true, window, cx);
12037            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
12038        });
12039    }
12040
12041    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
12042        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12043        let text_layout_details = &self.text_layout_details(window);
12044        self.transact(window, cx, |this, window, cx| {
12045            let edits = this.change_selections(Default::default(), window, cx, |s| {
12046                let mut edits: Vec<(Range<usize>, String)> = Default::default();
12047                s.move_with(|display_map, selection| {
12048                    if !selection.is_empty() {
12049                        return;
12050                    }
12051
12052                    let mut head = selection.head();
12053                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
12054                    if head.column() == display_map.line_len(head.row()) {
12055                        transpose_offset = display_map
12056                            .buffer_snapshot()
12057                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
12058                    }
12059
12060                    if transpose_offset == 0 {
12061                        return;
12062                    }
12063
12064                    *head.column_mut() += 1;
12065                    head = display_map.clip_point(head, Bias::Right);
12066                    let goal = SelectionGoal::HorizontalPosition(
12067                        display_map
12068                            .x_for_display_point(head, text_layout_details)
12069                            .into(),
12070                    );
12071                    selection.collapse_to(head, goal);
12072
12073                    let transpose_start = display_map
12074                        .buffer_snapshot()
12075                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
12076                    if edits.last().is_none_or(|e| e.0.end <= transpose_start) {
12077                        let transpose_end = display_map
12078                            .buffer_snapshot()
12079                            .clip_offset(transpose_offset + 1, Bias::Right);
12080                        if let Some(ch) = display_map
12081                            .buffer_snapshot()
12082                            .chars_at(transpose_start)
12083                            .next()
12084                        {
12085                            edits.push((transpose_start..transpose_offset, String::new()));
12086                            edits.push((transpose_end..transpose_end, ch.to_string()));
12087                        }
12088                    }
12089                });
12090                edits
12091            });
12092            this.buffer
12093                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12094            let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
12095            this.change_selections(Default::default(), window, cx, |s| {
12096                s.select(selections);
12097            });
12098        });
12099    }
12100
12101    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
12102        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12103        if self.mode.is_single_line() {
12104            cx.propagate();
12105            return;
12106        }
12107
12108        self.rewrap_impl(RewrapOptions::default(), cx)
12109    }
12110
12111    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
12112        let buffer = self.buffer.read(cx).snapshot(cx);
12113        let selections = self.selections.all::<Point>(&self.display_snapshot(cx));
12114
12115        #[derive(Clone, Debug, PartialEq)]
12116        enum CommentFormat {
12117            /// single line comment, with prefix for line
12118            Line(String),
12119            /// single line within a block comment, with prefix for line
12120            BlockLine(String),
12121            /// a single line of a block comment that includes the initial delimiter
12122            BlockCommentWithStart(BlockCommentConfig),
12123            /// a single line of a block comment that includes the ending delimiter
12124            BlockCommentWithEnd(BlockCommentConfig),
12125        }
12126
12127        // Split selections to respect paragraph, indent, and comment prefix boundaries.
12128        let wrap_ranges = selections.into_iter().flat_map(|selection| {
12129            let mut non_blank_rows_iter = (selection.start.row..=selection.end.row)
12130                .filter(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
12131                .peekable();
12132
12133            let first_row = if let Some(&row) = non_blank_rows_iter.peek() {
12134                row
12135            } else {
12136                return Vec::new();
12137            };
12138
12139            let language_settings = buffer.language_settings_at(selection.head(), cx);
12140            let language_scope = buffer.language_scope_at(selection.head());
12141
12142            let indent_and_prefix_for_row =
12143                |row: u32| -> (IndentSize, Option<CommentFormat>, Option<String>) {
12144                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
12145                    let (comment_prefix, rewrap_prefix) = if let Some(language_scope) =
12146                        &language_scope
12147                    {
12148                        let indent_end = Point::new(row, indent.len);
12149                        let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
12150                        let line_text_after_indent = buffer
12151                            .text_for_range(indent_end..line_end)
12152                            .collect::<String>();
12153
12154                        let is_within_comment_override = buffer
12155                            .language_scope_at(indent_end)
12156                            .is_some_and(|scope| scope.override_name() == Some("comment"));
12157                        let comment_delimiters = if is_within_comment_override {
12158                            // we are within a comment syntax node, but we don't
12159                            // yet know what kind of comment: block, doc or line
12160                            match (
12161                                language_scope.documentation_comment(),
12162                                language_scope.block_comment(),
12163                            ) {
12164                                (Some(config), _) | (_, Some(config))
12165                                    if buffer.contains_str_at(indent_end, &config.start) =>
12166                                {
12167                                    Some(CommentFormat::BlockCommentWithStart(config.clone()))
12168                                }
12169                                (Some(config), _) | (_, Some(config))
12170                                    if line_text_after_indent.ends_with(config.end.as_ref()) =>
12171                                {
12172                                    Some(CommentFormat::BlockCommentWithEnd(config.clone()))
12173                                }
12174                                (Some(config), _) | (_, Some(config))
12175                                    if buffer.contains_str_at(indent_end, &config.prefix) =>
12176                                {
12177                                    Some(CommentFormat::BlockLine(config.prefix.to_string()))
12178                                }
12179                                (_, _) => language_scope
12180                                    .line_comment_prefixes()
12181                                    .iter()
12182                                    .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12183                                    .map(|prefix| CommentFormat::Line(prefix.to_string())),
12184                            }
12185                        } else {
12186                            // we not in an overridden comment node, but we may
12187                            // be within a non-overridden line comment node
12188                            language_scope
12189                                .line_comment_prefixes()
12190                                .iter()
12191                                .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12192                                .map(|prefix| CommentFormat::Line(prefix.to_string()))
12193                        };
12194
12195                        let rewrap_prefix = language_scope
12196                            .rewrap_prefixes()
12197                            .iter()
12198                            .find_map(|prefix_regex| {
12199                                prefix_regex.find(&line_text_after_indent).map(|mat| {
12200                                    if mat.start() == 0 {
12201                                        Some(mat.as_str().to_string())
12202                                    } else {
12203                                        None
12204                                    }
12205                                })
12206                            })
12207                            .flatten();
12208                        (comment_delimiters, rewrap_prefix)
12209                    } else {
12210                        (None, None)
12211                    };
12212                    (indent, comment_prefix, rewrap_prefix)
12213                };
12214
12215            let mut ranges = Vec::new();
12216            let from_empty_selection = selection.is_empty();
12217
12218            let mut current_range_start = first_row;
12219            let mut prev_row = first_row;
12220            let (
12221                mut current_range_indent,
12222                mut current_range_comment_delimiters,
12223                mut current_range_rewrap_prefix,
12224            ) = indent_and_prefix_for_row(first_row);
12225
12226            for row in non_blank_rows_iter.skip(1) {
12227                let has_paragraph_break = row > prev_row + 1;
12228
12229                let (row_indent, row_comment_delimiters, row_rewrap_prefix) =
12230                    indent_and_prefix_for_row(row);
12231
12232                let has_indent_change = row_indent != current_range_indent;
12233                let has_comment_change = row_comment_delimiters != current_range_comment_delimiters;
12234
12235                let has_boundary_change = has_comment_change
12236                    || row_rewrap_prefix.is_some()
12237                    || (has_indent_change && current_range_comment_delimiters.is_some());
12238
12239                if has_paragraph_break || has_boundary_change {
12240                    ranges.push((
12241                        language_settings.clone(),
12242                        Point::new(current_range_start, 0)
12243                            ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12244                        current_range_indent,
12245                        current_range_comment_delimiters.clone(),
12246                        current_range_rewrap_prefix.clone(),
12247                        from_empty_selection,
12248                    ));
12249                    current_range_start = row;
12250                    current_range_indent = row_indent;
12251                    current_range_comment_delimiters = row_comment_delimiters;
12252                    current_range_rewrap_prefix = row_rewrap_prefix;
12253                }
12254                prev_row = row;
12255            }
12256
12257            ranges.push((
12258                language_settings.clone(),
12259                Point::new(current_range_start, 0)
12260                    ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12261                current_range_indent,
12262                current_range_comment_delimiters,
12263                current_range_rewrap_prefix,
12264                from_empty_selection,
12265            ));
12266
12267            ranges
12268        });
12269
12270        let mut edits = Vec::new();
12271        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
12272
12273        for (
12274            language_settings,
12275            wrap_range,
12276            mut indent_size,
12277            comment_prefix,
12278            rewrap_prefix,
12279            from_empty_selection,
12280        ) in wrap_ranges
12281        {
12282            let mut start_row = wrap_range.start.row;
12283            let mut end_row = wrap_range.end.row;
12284
12285            // Skip selections that overlap with a range that has already been rewrapped.
12286            let selection_range = start_row..end_row;
12287            if rewrapped_row_ranges
12288                .iter()
12289                .any(|range| range.overlaps(&selection_range))
12290            {
12291                continue;
12292            }
12293
12294            let tab_size = language_settings.tab_size;
12295
12296            let (line_prefix, inside_comment) = match &comment_prefix {
12297                Some(CommentFormat::Line(prefix) | CommentFormat::BlockLine(prefix)) => {
12298                    (Some(prefix.as_str()), true)
12299                }
12300                Some(CommentFormat::BlockCommentWithEnd(BlockCommentConfig { prefix, .. })) => {
12301                    (Some(prefix.as_ref()), true)
12302                }
12303                Some(CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12304                    start: _,
12305                    end: _,
12306                    prefix,
12307                    tab_size,
12308                })) => {
12309                    indent_size.len += tab_size;
12310                    (Some(prefix.as_ref()), true)
12311                }
12312                None => (None, false),
12313            };
12314            let indent_prefix = indent_size.chars().collect::<String>();
12315            let line_prefix = format!("{indent_prefix}{}", line_prefix.unwrap_or(""));
12316
12317            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
12318                RewrapBehavior::InComments => inside_comment,
12319                RewrapBehavior::InSelections => !wrap_range.is_empty(),
12320                RewrapBehavior::Anywhere => true,
12321            };
12322
12323            let should_rewrap = options.override_language_settings
12324                || allow_rewrap_based_on_language
12325                || self.hard_wrap.is_some();
12326            if !should_rewrap {
12327                continue;
12328            }
12329
12330            if from_empty_selection {
12331                'expand_upwards: while start_row > 0 {
12332                    let prev_row = start_row - 1;
12333                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
12334                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
12335                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
12336                    {
12337                        start_row = prev_row;
12338                    } else {
12339                        break 'expand_upwards;
12340                    }
12341                }
12342
12343                'expand_downwards: while end_row < buffer.max_point().row {
12344                    let next_row = end_row + 1;
12345                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
12346                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
12347                        && !buffer.is_line_blank(MultiBufferRow(next_row))
12348                    {
12349                        end_row = next_row;
12350                    } else {
12351                        break 'expand_downwards;
12352                    }
12353                }
12354            }
12355
12356            let start = Point::new(start_row, 0);
12357            let start_offset = ToOffset::to_offset(&start, &buffer);
12358            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
12359            let selection_text = buffer.text_for_range(start..end).collect::<String>();
12360            let mut first_line_delimiter = None;
12361            let mut last_line_delimiter = None;
12362            let Some(lines_without_prefixes) = selection_text
12363                .lines()
12364                .enumerate()
12365                .map(|(ix, line)| {
12366                    let line_trimmed = line.trim_start();
12367                    if rewrap_prefix.is_some() && ix > 0 {
12368                        Ok(line_trimmed)
12369                    } else if let Some(
12370                        CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12371                            start,
12372                            prefix,
12373                            end,
12374                            tab_size,
12375                        })
12376                        | CommentFormat::BlockCommentWithEnd(BlockCommentConfig {
12377                            start,
12378                            prefix,
12379                            end,
12380                            tab_size,
12381                        }),
12382                    ) = &comment_prefix
12383                    {
12384                        let line_trimmed = line_trimmed
12385                            .strip_prefix(start.as_ref())
12386                            .map(|s| {
12387                                let mut indent_size = indent_size;
12388                                indent_size.len -= tab_size;
12389                                let indent_prefix: String = indent_size.chars().collect();
12390                                first_line_delimiter = Some((indent_prefix, start));
12391                                s.trim_start()
12392                            })
12393                            .unwrap_or(line_trimmed);
12394                        let line_trimmed = line_trimmed
12395                            .strip_suffix(end.as_ref())
12396                            .map(|s| {
12397                                last_line_delimiter = Some(end);
12398                                s.trim_end()
12399                            })
12400                            .unwrap_or(line_trimmed);
12401                        let line_trimmed = line_trimmed
12402                            .strip_prefix(prefix.as_ref())
12403                            .unwrap_or(line_trimmed);
12404                        Ok(line_trimmed)
12405                    } else if let Some(CommentFormat::BlockLine(prefix)) = &comment_prefix {
12406                        line_trimmed.strip_prefix(prefix).with_context(|| {
12407                            format!("line did not start with prefix {prefix:?}: {line:?}")
12408                        })
12409                    } else {
12410                        line_trimmed
12411                            .strip_prefix(&line_prefix.trim_start())
12412                            .with_context(|| {
12413                                format!("line did not start with prefix {line_prefix:?}: {line:?}")
12414                            })
12415                    }
12416                })
12417                .collect::<Result<Vec<_>, _>>()
12418                .log_err()
12419            else {
12420                continue;
12421            };
12422
12423            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
12424                buffer
12425                    .language_settings_at(Point::new(start_row, 0), cx)
12426                    .preferred_line_length as usize
12427            });
12428
12429            let subsequent_lines_prefix = if let Some(rewrap_prefix_str) = &rewrap_prefix {
12430                format!("{}{}", indent_prefix, " ".repeat(rewrap_prefix_str.len()))
12431            } else {
12432                line_prefix.clone()
12433            };
12434
12435            let wrapped_text = {
12436                let mut wrapped_text = wrap_with_prefix(
12437                    line_prefix,
12438                    subsequent_lines_prefix,
12439                    lines_without_prefixes.join("\n"),
12440                    wrap_column,
12441                    tab_size,
12442                    options.preserve_existing_whitespace,
12443                );
12444
12445                if let Some((indent, delimiter)) = first_line_delimiter {
12446                    wrapped_text = format!("{indent}{delimiter}\n{wrapped_text}");
12447                }
12448                if let Some(last_line) = last_line_delimiter {
12449                    wrapped_text = format!("{wrapped_text}\n{indent_prefix}{last_line}");
12450                }
12451
12452                wrapped_text
12453            };
12454
12455            // TODO: should always use char-based diff while still supporting cursor behavior that
12456            // matches vim.
12457            let mut diff_options = DiffOptions::default();
12458            if options.override_language_settings {
12459                diff_options.max_word_diff_len = 0;
12460                diff_options.max_word_diff_line_count = 0;
12461            } else {
12462                diff_options.max_word_diff_len = usize::MAX;
12463                diff_options.max_word_diff_line_count = usize::MAX;
12464            }
12465
12466            for (old_range, new_text) in
12467                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
12468            {
12469                let edit_start = buffer.anchor_after(start_offset + old_range.start);
12470                let edit_end = buffer.anchor_after(start_offset + old_range.end);
12471                edits.push((edit_start..edit_end, new_text));
12472            }
12473
12474            rewrapped_row_ranges.push(start_row..=end_row);
12475        }
12476
12477        self.buffer
12478            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12479    }
12480
12481    pub fn cut_common(
12482        &mut self,
12483        cut_no_selection_line: bool,
12484        window: &mut Window,
12485        cx: &mut Context<Self>,
12486    ) -> ClipboardItem {
12487        let mut text = String::new();
12488        let buffer = self.buffer.read(cx).snapshot(cx);
12489        let mut selections = self.selections.all::<Point>(&self.display_snapshot(cx));
12490        let mut clipboard_selections = Vec::with_capacity(selections.len());
12491        {
12492            let max_point = buffer.max_point();
12493            let mut is_first = true;
12494            for selection in &mut selections {
12495                let is_entire_line =
12496                    (selection.is_empty() && cut_no_selection_line) || self.selections.line_mode();
12497                if is_entire_line {
12498                    selection.start = Point::new(selection.start.row, 0);
12499                    if !selection.is_empty() && selection.end.column == 0 {
12500                        selection.end = cmp::min(max_point, selection.end);
12501                    } else {
12502                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
12503                    }
12504                    selection.goal = SelectionGoal::None;
12505                }
12506                if is_first {
12507                    is_first = false;
12508                } else {
12509                    text += "\n";
12510                }
12511                let mut len = 0;
12512                for chunk in buffer.text_for_range(selection.start..selection.end) {
12513                    text.push_str(chunk);
12514                    len += chunk.len();
12515                }
12516                clipboard_selections.push(ClipboardSelection {
12517                    len,
12518                    is_entire_line,
12519                    first_line_indent: buffer
12520                        .indent_size_for_line(MultiBufferRow(selection.start.row))
12521                        .len,
12522                });
12523            }
12524        }
12525
12526        self.transact(window, cx, |this, window, cx| {
12527            this.change_selections(Default::default(), window, cx, |s| {
12528                s.select(selections);
12529            });
12530            this.insert("", window, cx);
12531        });
12532        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
12533    }
12534
12535    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
12536        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12537        let item = self.cut_common(true, window, cx);
12538        cx.write_to_clipboard(item);
12539    }
12540
12541    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
12542        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12543        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12544            s.move_with(|snapshot, sel| {
12545                if sel.is_empty() {
12546                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()));
12547                }
12548                if sel.is_empty() {
12549                    sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
12550                }
12551            });
12552        });
12553        let item = self.cut_common(false, window, cx);
12554        cx.set_global(KillRing(item))
12555    }
12556
12557    pub fn kill_ring_yank(
12558        &mut self,
12559        _: &KillRingYank,
12560        window: &mut Window,
12561        cx: &mut Context<Self>,
12562    ) {
12563        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12564        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
12565            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
12566                (kill_ring.text().to_string(), kill_ring.metadata_json())
12567            } else {
12568                return;
12569            }
12570        } else {
12571            return;
12572        };
12573        self.do_paste(&text, metadata, false, window, cx);
12574    }
12575
12576    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
12577        self.do_copy(true, cx);
12578    }
12579
12580    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
12581        self.do_copy(false, cx);
12582    }
12583
12584    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
12585        let selections = self.selections.all::<Point>(&self.display_snapshot(cx));
12586        let buffer = self.buffer.read(cx).read(cx);
12587        let mut text = String::new();
12588
12589        let mut clipboard_selections = Vec::with_capacity(selections.len());
12590        {
12591            let max_point = buffer.max_point();
12592            let mut is_first = true;
12593            for selection in &selections {
12594                let mut start = selection.start;
12595                let mut end = selection.end;
12596                let is_entire_line = selection.is_empty() || self.selections.line_mode();
12597                let mut add_trailing_newline = false;
12598                if is_entire_line {
12599                    start = Point::new(start.row, 0);
12600                    let next_line_start = Point::new(end.row + 1, 0);
12601                    if next_line_start <= max_point {
12602                        end = next_line_start;
12603                    } else {
12604                        // We're on the last line without a trailing newline.
12605                        // Copy to the end of the line and add a newline afterwards.
12606                        end = Point::new(end.row, buffer.line_len(MultiBufferRow(end.row)));
12607                        add_trailing_newline = true;
12608                    }
12609                }
12610
12611                let mut trimmed_selections = Vec::new();
12612                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
12613                    let row = MultiBufferRow(start.row);
12614                    let first_indent = buffer.indent_size_for_line(row);
12615                    if first_indent.len == 0 || start.column > first_indent.len {
12616                        trimmed_selections.push(start..end);
12617                    } else {
12618                        trimmed_selections.push(
12619                            Point::new(row.0, first_indent.len)
12620                                ..Point::new(row.0, buffer.line_len(row)),
12621                        );
12622                        for row in start.row + 1..=end.row {
12623                            let mut line_len = buffer.line_len(MultiBufferRow(row));
12624                            if row == end.row {
12625                                line_len = end.column;
12626                            }
12627                            if line_len == 0 {
12628                                trimmed_selections
12629                                    .push(Point::new(row, 0)..Point::new(row, line_len));
12630                                continue;
12631                            }
12632                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
12633                            if row_indent_size.len >= first_indent.len {
12634                                trimmed_selections.push(
12635                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
12636                                );
12637                            } else {
12638                                trimmed_selections.clear();
12639                                trimmed_selections.push(start..end);
12640                                break;
12641                            }
12642                        }
12643                    }
12644                } else {
12645                    trimmed_selections.push(start..end);
12646                }
12647
12648                for trimmed_range in trimmed_selections {
12649                    if is_first {
12650                        is_first = false;
12651                    } else {
12652                        text += "\n";
12653                    }
12654                    let mut len = 0;
12655                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
12656                        text.push_str(chunk);
12657                        len += chunk.len();
12658                    }
12659                    if add_trailing_newline {
12660                        text.push('\n');
12661                        len += 1;
12662                    }
12663                    clipboard_selections.push(ClipboardSelection {
12664                        len,
12665                        is_entire_line,
12666                        first_line_indent: buffer
12667                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
12668                            .len,
12669                    });
12670                }
12671            }
12672        }
12673
12674        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
12675            text,
12676            clipboard_selections,
12677        ));
12678    }
12679
12680    pub fn do_paste(
12681        &mut self,
12682        text: &String,
12683        clipboard_selections: Option<Vec<ClipboardSelection>>,
12684        handle_entire_lines: bool,
12685        window: &mut Window,
12686        cx: &mut Context<Self>,
12687    ) {
12688        if self.read_only(cx) {
12689            return;
12690        }
12691
12692        let clipboard_text = Cow::Borrowed(text.as_str());
12693
12694        self.transact(window, cx, |this, window, cx| {
12695            let had_active_edit_prediction = this.has_active_edit_prediction();
12696            let display_map = this.display_snapshot(cx);
12697            let old_selections = this.selections.all::<usize>(&display_map);
12698            let cursor_offset = this.selections.last::<usize>(&display_map).head();
12699
12700            if let Some(mut clipboard_selections) = clipboard_selections {
12701                let all_selections_were_entire_line =
12702                    clipboard_selections.iter().all(|s| s.is_entire_line);
12703                let first_selection_indent_column =
12704                    clipboard_selections.first().map(|s| s.first_line_indent);
12705                if clipboard_selections.len() != old_selections.len() {
12706                    clipboard_selections.drain(..);
12707                }
12708                let mut auto_indent_on_paste = true;
12709
12710                this.buffer.update(cx, |buffer, cx| {
12711                    let snapshot = buffer.read(cx);
12712                    auto_indent_on_paste = snapshot
12713                        .language_settings_at(cursor_offset, cx)
12714                        .auto_indent_on_paste;
12715
12716                    let mut start_offset = 0;
12717                    let mut edits = Vec::new();
12718                    let mut original_indent_columns = Vec::new();
12719                    for (ix, selection) in old_selections.iter().enumerate() {
12720                        let to_insert;
12721                        let entire_line;
12722                        let original_indent_column;
12723                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
12724                            let end_offset = start_offset + clipboard_selection.len;
12725                            to_insert = &clipboard_text[start_offset..end_offset];
12726                            entire_line = clipboard_selection.is_entire_line;
12727                            start_offset = end_offset + 1;
12728                            original_indent_column = Some(clipboard_selection.first_line_indent);
12729                        } else {
12730                            to_insert = &*clipboard_text;
12731                            entire_line = all_selections_were_entire_line;
12732                            original_indent_column = first_selection_indent_column
12733                        }
12734
12735                        let (range, to_insert) =
12736                            if selection.is_empty() && handle_entire_lines && entire_line {
12737                                // If the corresponding selection was empty when this slice of the
12738                                // clipboard text was written, then the entire line containing the
12739                                // selection was copied. If this selection is also currently empty,
12740                                // then paste the line before the current line of the buffer.
12741                                let column = selection.start.to_point(&snapshot).column as usize;
12742                                let line_start = selection.start - column;
12743                                (line_start..line_start, Cow::Borrowed(to_insert))
12744                            } else {
12745                                let language = snapshot.language_at(selection.head());
12746                                let range = selection.range();
12747                                if let Some(language) = language
12748                                    && language.name() == "Markdown".into()
12749                                {
12750                                    edit_for_markdown_paste(
12751                                        &snapshot,
12752                                        range,
12753                                        to_insert,
12754                                        url::Url::parse(to_insert).ok(),
12755                                    )
12756                                } else {
12757                                    (range, Cow::Borrowed(to_insert))
12758                                }
12759                            };
12760
12761                        edits.push((range, to_insert));
12762                        original_indent_columns.push(original_indent_column);
12763                    }
12764                    drop(snapshot);
12765
12766                    buffer.edit(
12767                        edits,
12768                        if auto_indent_on_paste {
12769                            Some(AutoindentMode::Block {
12770                                original_indent_columns,
12771                            })
12772                        } else {
12773                            None
12774                        },
12775                        cx,
12776                    );
12777                });
12778
12779                let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
12780                this.change_selections(Default::default(), window, cx, |s| s.select(selections));
12781            } else {
12782                let url = url::Url::parse(&clipboard_text).ok();
12783
12784                let auto_indent_mode = if !clipboard_text.is_empty() {
12785                    Some(AutoindentMode::Block {
12786                        original_indent_columns: Vec::new(),
12787                    })
12788                } else {
12789                    None
12790                };
12791
12792                let selection_anchors = this.buffer.update(cx, |buffer, cx| {
12793                    let snapshot = buffer.snapshot(cx);
12794
12795                    let anchors = old_selections
12796                        .iter()
12797                        .map(|s| {
12798                            let anchor = snapshot.anchor_after(s.head());
12799                            s.map(|_| anchor)
12800                        })
12801                        .collect::<Vec<_>>();
12802
12803                    let mut edits = Vec::new();
12804
12805                    for selection in old_selections.iter() {
12806                        let language = snapshot.language_at(selection.head());
12807                        let range = selection.range();
12808
12809                        let (edit_range, edit_text) = if let Some(language) = language
12810                            && language.name() == "Markdown".into()
12811                        {
12812                            edit_for_markdown_paste(&snapshot, range, &clipboard_text, url.clone())
12813                        } else {
12814                            (range, clipboard_text.clone())
12815                        };
12816
12817                        edits.push((edit_range, edit_text));
12818                    }
12819
12820                    drop(snapshot);
12821                    buffer.edit(edits, auto_indent_mode, cx);
12822
12823                    anchors
12824                });
12825
12826                this.change_selections(Default::default(), window, cx, |s| {
12827                    s.select_anchors(selection_anchors);
12828                });
12829            }
12830
12831            let trigger_in_words =
12832                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
12833
12834            this.trigger_completion_on_input(text, trigger_in_words, window, cx);
12835        });
12836    }
12837
12838    pub fn diff_clipboard_with_selection(
12839        &mut self,
12840        _: &DiffClipboardWithSelection,
12841        window: &mut Window,
12842        cx: &mut Context<Self>,
12843    ) {
12844        let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
12845
12846        if selections.is_empty() {
12847            log::warn!("There should always be at least one selection in Zed. This is a bug.");
12848            return;
12849        };
12850
12851        let clipboard_text = match cx.read_from_clipboard() {
12852            Some(item) => match item.entries().first() {
12853                Some(ClipboardEntry::String(text)) => Some(text.text().to_string()),
12854                _ => None,
12855            },
12856            None => None,
12857        };
12858
12859        let Some(clipboard_text) = clipboard_text else {
12860            log::warn!("Clipboard doesn't contain text.");
12861            return;
12862        };
12863
12864        window.dispatch_action(
12865            Box::new(DiffClipboardWithSelectionData {
12866                clipboard_text,
12867                editor: cx.entity(),
12868            }),
12869            cx,
12870        );
12871    }
12872
12873    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
12874        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12875        if let Some(item) = cx.read_from_clipboard() {
12876            let entries = item.entries();
12877
12878            match entries.first() {
12879                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
12880                // of all the pasted entries.
12881                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
12882                    .do_paste(
12883                        clipboard_string.text(),
12884                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
12885                        true,
12886                        window,
12887                        cx,
12888                    ),
12889                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
12890            }
12891        }
12892    }
12893
12894    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
12895        if self.read_only(cx) {
12896            return;
12897        }
12898
12899        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12900
12901        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
12902            if let Some((selections, _)) =
12903                self.selection_history.transaction(transaction_id).cloned()
12904            {
12905                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12906                    s.select_anchors(selections.to_vec());
12907                });
12908            } else {
12909                log::error!(
12910                    "No entry in selection_history found for undo. \
12911                     This may correspond to a bug where undo does not update the selection. \
12912                     If this is occurring, please add details to \
12913                     https://github.com/zed-industries/zed/issues/22692"
12914                );
12915            }
12916            self.request_autoscroll(Autoscroll::fit(), cx);
12917            self.unmark_text(window, cx);
12918            self.refresh_edit_prediction(true, false, window, cx);
12919            cx.emit(EditorEvent::Edited { transaction_id });
12920            cx.emit(EditorEvent::TransactionUndone { transaction_id });
12921        }
12922    }
12923
12924    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
12925        if self.read_only(cx) {
12926            return;
12927        }
12928
12929        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12930
12931        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
12932            if let Some((_, Some(selections))) =
12933                self.selection_history.transaction(transaction_id).cloned()
12934            {
12935                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12936                    s.select_anchors(selections.to_vec());
12937                });
12938            } else {
12939                log::error!(
12940                    "No entry in selection_history found for redo. \
12941                     This may correspond to a bug where undo does not update the selection. \
12942                     If this is occurring, please add details to \
12943                     https://github.com/zed-industries/zed/issues/22692"
12944                );
12945            }
12946            self.request_autoscroll(Autoscroll::fit(), cx);
12947            self.unmark_text(window, cx);
12948            self.refresh_edit_prediction(true, false, window, cx);
12949            cx.emit(EditorEvent::Edited { transaction_id });
12950        }
12951    }
12952
12953    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
12954        self.buffer
12955            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
12956    }
12957
12958    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
12959        self.buffer
12960            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
12961    }
12962
12963    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
12964        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12965        self.change_selections(Default::default(), window, cx, |s| {
12966            s.move_with(|map, selection| {
12967                let cursor = if selection.is_empty() {
12968                    movement::left(map, selection.start)
12969                } else {
12970                    selection.start
12971                };
12972                selection.collapse_to(cursor, SelectionGoal::None);
12973            });
12974        })
12975    }
12976
12977    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
12978        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12979        self.change_selections(Default::default(), window, cx, |s| {
12980            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
12981        })
12982    }
12983
12984    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
12985        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12986        self.change_selections(Default::default(), window, cx, |s| {
12987            s.move_with(|map, selection| {
12988                let cursor = if selection.is_empty() {
12989                    movement::right(map, selection.end)
12990                } else {
12991                    selection.end
12992                };
12993                selection.collapse_to(cursor, SelectionGoal::None)
12994            });
12995        })
12996    }
12997
12998    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
12999        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13000        self.change_selections(Default::default(), window, cx, |s| {
13001            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
13002        });
13003    }
13004
13005    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
13006        if self.take_rename(true, window, cx).is_some() {
13007            return;
13008        }
13009
13010        if self.mode.is_single_line() {
13011            cx.propagate();
13012            return;
13013        }
13014
13015        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13016
13017        let text_layout_details = &self.text_layout_details(window);
13018        let selection_count = self.selections.count();
13019        let first_selection = self.selections.first_anchor();
13020
13021        self.change_selections(Default::default(), window, cx, |s| {
13022            s.move_with(|map, selection| {
13023                if !selection.is_empty() {
13024                    selection.goal = SelectionGoal::None;
13025                }
13026                let (cursor, goal) = movement::up(
13027                    map,
13028                    selection.start,
13029                    selection.goal,
13030                    false,
13031                    text_layout_details,
13032                );
13033                selection.collapse_to(cursor, goal);
13034            });
13035        });
13036
13037        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
13038        {
13039            cx.propagate();
13040        }
13041    }
13042
13043    pub fn move_up_by_lines(
13044        &mut self,
13045        action: &MoveUpByLines,
13046        window: &mut Window,
13047        cx: &mut Context<Self>,
13048    ) {
13049        if self.take_rename(true, window, cx).is_some() {
13050            return;
13051        }
13052
13053        if self.mode.is_single_line() {
13054            cx.propagate();
13055            return;
13056        }
13057
13058        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13059
13060        let text_layout_details = &self.text_layout_details(window);
13061
13062        self.change_selections(Default::default(), window, cx, |s| {
13063            s.move_with(|map, selection| {
13064                if !selection.is_empty() {
13065                    selection.goal = SelectionGoal::None;
13066                }
13067                let (cursor, goal) = movement::up_by_rows(
13068                    map,
13069                    selection.start,
13070                    action.lines,
13071                    selection.goal,
13072                    false,
13073                    text_layout_details,
13074                );
13075                selection.collapse_to(cursor, goal);
13076            });
13077        })
13078    }
13079
13080    pub fn move_down_by_lines(
13081        &mut self,
13082        action: &MoveDownByLines,
13083        window: &mut Window,
13084        cx: &mut Context<Self>,
13085    ) {
13086        if self.take_rename(true, window, cx).is_some() {
13087            return;
13088        }
13089
13090        if self.mode.is_single_line() {
13091            cx.propagate();
13092            return;
13093        }
13094
13095        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13096
13097        let text_layout_details = &self.text_layout_details(window);
13098
13099        self.change_selections(Default::default(), window, cx, |s| {
13100            s.move_with(|map, selection| {
13101                if !selection.is_empty() {
13102                    selection.goal = SelectionGoal::None;
13103                }
13104                let (cursor, goal) = movement::down_by_rows(
13105                    map,
13106                    selection.start,
13107                    action.lines,
13108                    selection.goal,
13109                    false,
13110                    text_layout_details,
13111                );
13112                selection.collapse_to(cursor, goal);
13113            });
13114        })
13115    }
13116
13117    pub fn select_down_by_lines(
13118        &mut self,
13119        action: &SelectDownByLines,
13120        window: &mut Window,
13121        cx: &mut Context<Self>,
13122    ) {
13123        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13124        let text_layout_details = &self.text_layout_details(window);
13125        self.change_selections(Default::default(), window, cx, |s| {
13126            s.move_heads_with(|map, head, goal| {
13127                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
13128            })
13129        })
13130    }
13131
13132    pub fn select_up_by_lines(
13133        &mut self,
13134        action: &SelectUpByLines,
13135        window: &mut Window,
13136        cx: &mut Context<Self>,
13137    ) {
13138        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13139        let text_layout_details = &self.text_layout_details(window);
13140        self.change_selections(Default::default(), window, cx, |s| {
13141            s.move_heads_with(|map, head, goal| {
13142                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
13143            })
13144        })
13145    }
13146
13147    pub fn select_page_up(
13148        &mut self,
13149        _: &SelectPageUp,
13150        window: &mut Window,
13151        cx: &mut Context<Self>,
13152    ) {
13153        let Some(row_count) = self.visible_row_count() else {
13154            return;
13155        };
13156
13157        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13158
13159        let text_layout_details = &self.text_layout_details(window);
13160
13161        self.change_selections(Default::default(), window, cx, |s| {
13162            s.move_heads_with(|map, head, goal| {
13163                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
13164            })
13165        })
13166    }
13167
13168    pub fn move_page_up(
13169        &mut self,
13170        action: &MovePageUp,
13171        window: &mut Window,
13172        cx: &mut Context<Self>,
13173    ) {
13174        if self.take_rename(true, window, cx).is_some() {
13175            return;
13176        }
13177
13178        if self
13179            .context_menu
13180            .borrow_mut()
13181            .as_mut()
13182            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
13183            .unwrap_or(false)
13184        {
13185            return;
13186        }
13187
13188        if matches!(self.mode, EditorMode::SingleLine) {
13189            cx.propagate();
13190            return;
13191        }
13192
13193        let Some(row_count) = self.visible_row_count() else {
13194            return;
13195        };
13196
13197        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13198
13199        let effects = if action.center_cursor {
13200            SelectionEffects::scroll(Autoscroll::center())
13201        } else {
13202            SelectionEffects::default()
13203        };
13204
13205        let text_layout_details = &self.text_layout_details(window);
13206
13207        self.change_selections(effects, window, cx, |s| {
13208            s.move_with(|map, selection| {
13209                if !selection.is_empty() {
13210                    selection.goal = SelectionGoal::None;
13211                }
13212                let (cursor, goal) = movement::up_by_rows(
13213                    map,
13214                    selection.end,
13215                    row_count,
13216                    selection.goal,
13217                    false,
13218                    text_layout_details,
13219                );
13220                selection.collapse_to(cursor, goal);
13221            });
13222        });
13223    }
13224
13225    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
13226        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13227        let text_layout_details = &self.text_layout_details(window);
13228        self.change_selections(Default::default(), window, cx, |s| {
13229            s.move_heads_with(|map, head, goal| {
13230                movement::up(map, head, goal, false, text_layout_details)
13231            })
13232        })
13233    }
13234
13235    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
13236        self.take_rename(true, window, cx);
13237
13238        if self.mode.is_single_line() {
13239            cx.propagate();
13240            return;
13241        }
13242
13243        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13244
13245        let text_layout_details = &self.text_layout_details(window);
13246        let selection_count = self.selections.count();
13247        let first_selection = self.selections.first_anchor();
13248
13249        self.change_selections(Default::default(), window, cx, |s| {
13250            s.move_with(|map, selection| {
13251                if !selection.is_empty() {
13252                    selection.goal = SelectionGoal::None;
13253                }
13254                let (cursor, goal) = movement::down(
13255                    map,
13256                    selection.end,
13257                    selection.goal,
13258                    false,
13259                    text_layout_details,
13260                );
13261                selection.collapse_to(cursor, goal);
13262            });
13263        });
13264
13265        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
13266        {
13267            cx.propagate();
13268        }
13269    }
13270
13271    pub fn select_page_down(
13272        &mut self,
13273        _: &SelectPageDown,
13274        window: &mut Window,
13275        cx: &mut Context<Self>,
13276    ) {
13277        let Some(row_count) = self.visible_row_count() else {
13278            return;
13279        };
13280
13281        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13282
13283        let text_layout_details = &self.text_layout_details(window);
13284
13285        self.change_selections(Default::default(), window, cx, |s| {
13286            s.move_heads_with(|map, head, goal| {
13287                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
13288            })
13289        })
13290    }
13291
13292    pub fn move_page_down(
13293        &mut self,
13294        action: &MovePageDown,
13295        window: &mut Window,
13296        cx: &mut Context<Self>,
13297    ) {
13298        if self.take_rename(true, window, cx).is_some() {
13299            return;
13300        }
13301
13302        if self
13303            .context_menu
13304            .borrow_mut()
13305            .as_mut()
13306            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
13307            .unwrap_or(false)
13308        {
13309            return;
13310        }
13311
13312        if matches!(self.mode, EditorMode::SingleLine) {
13313            cx.propagate();
13314            return;
13315        }
13316
13317        let Some(row_count) = self.visible_row_count() else {
13318            return;
13319        };
13320
13321        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13322
13323        let effects = if action.center_cursor {
13324            SelectionEffects::scroll(Autoscroll::center())
13325        } else {
13326            SelectionEffects::default()
13327        };
13328
13329        let text_layout_details = &self.text_layout_details(window);
13330        self.change_selections(effects, window, cx, |s| {
13331            s.move_with(|map, selection| {
13332                if !selection.is_empty() {
13333                    selection.goal = SelectionGoal::None;
13334                }
13335                let (cursor, goal) = movement::down_by_rows(
13336                    map,
13337                    selection.end,
13338                    row_count,
13339                    selection.goal,
13340                    false,
13341                    text_layout_details,
13342                );
13343                selection.collapse_to(cursor, goal);
13344            });
13345        });
13346    }
13347
13348    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
13349        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13350        let text_layout_details = &self.text_layout_details(window);
13351        self.change_selections(Default::default(), window, cx, |s| {
13352            s.move_heads_with(|map, head, goal| {
13353                movement::down(map, head, goal, false, text_layout_details)
13354            })
13355        });
13356    }
13357
13358    pub fn context_menu_first(
13359        &mut self,
13360        _: &ContextMenuFirst,
13361        window: &mut Window,
13362        cx: &mut Context<Self>,
13363    ) {
13364        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13365            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
13366        }
13367    }
13368
13369    pub fn context_menu_prev(
13370        &mut self,
13371        _: &ContextMenuPrevious,
13372        window: &mut Window,
13373        cx: &mut Context<Self>,
13374    ) {
13375        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13376            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
13377        }
13378    }
13379
13380    pub fn context_menu_next(
13381        &mut self,
13382        _: &ContextMenuNext,
13383        window: &mut Window,
13384        cx: &mut Context<Self>,
13385    ) {
13386        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13387            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
13388        }
13389    }
13390
13391    pub fn context_menu_last(
13392        &mut self,
13393        _: &ContextMenuLast,
13394        window: &mut Window,
13395        cx: &mut Context<Self>,
13396    ) {
13397        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13398            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
13399        }
13400    }
13401
13402    pub fn signature_help_prev(
13403        &mut self,
13404        _: &SignatureHelpPrevious,
13405        _: &mut Window,
13406        cx: &mut Context<Self>,
13407    ) {
13408        if let Some(popover) = self.signature_help_state.popover_mut() {
13409            if popover.current_signature == 0 {
13410                popover.current_signature = popover.signatures.len() - 1;
13411            } else {
13412                popover.current_signature -= 1;
13413            }
13414            cx.notify();
13415        }
13416    }
13417
13418    pub fn signature_help_next(
13419        &mut self,
13420        _: &SignatureHelpNext,
13421        _: &mut Window,
13422        cx: &mut Context<Self>,
13423    ) {
13424        if let Some(popover) = self.signature_help_state.popover_mut() {
13425            if popover.current_signature + 1 == popover.signatures.len() {
13426                popover.current_signature = 0;
13427            } else {
13428                popover.current_signature += 1;
13429            }
13430            cx.notify();
13431        }
13432    }
13433
13434    pub fn move_to_previous_word_start(
13435        &mut self,
13436        _: &MoveToPreviousWordStart,
13437        window: &mut Window,
13438        cx: &mut Context<Self>,
13439    ) {
13440        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13441        self.change_selections(Default::default(), window, cx, |s| {
13442            s.move_cursors_with(|map, head, _| {
13443                (
13444                    movement::previous_word_start(map, head),
13445                    SelectionGoal::None,
13446                )
13447            });
13448        })
13449    }
13450
13451    pub fn move_to_previous_subword_start(
13452        &mut self,
13453        _: &MoveToPreviousSubwordStart,
13454        window: &mut Window,
13455        cx: &mut Context<Self>,
13456    ) {
13457        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13458        self.change_selections(Default::default(), window, cx, |s| {
13459            s.move_cursors_with(|map, head, _| {
13460                (
13461                    movement::previous_subword_start(map, head),
13462                    SelectionGoal::None,
13463                )
13464            });
13465        })
13466    }
13467
13468    pub fn select_to_previous_word_start(
13469        &mut self,
13470        _: &SelectToPreviousWordStart,
13471        window: &mut Window,
13472        cx: &mut Context<Self>,
13473    ) {
13474        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13475        self.change_selections(Default::default(), window, cx, |s| {
13476            s.move_heads_with(|map, head, _| {
13477                (
13478                    movement::previous_word_start(map, head),
13479                    SelectionGoal::None,
13480                )
13481            });
13482        })
13483    }
13484
13485    pub fn select_to_previous_subword_start(
13486        &mut self,
13487        _: &SelectToPreviousSubwordStart,
13488        window: &mut Window,
13489        cx: &mut Context<Self>,
13490    ) {
13491        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13492        self.change_selections(Default::default(), window, cx, |s| {
13493            s.move_heads_with(|map, head, _| {
13494                (
13495                    movement::previous_subword_start(map, head),
13496                    SelectionGoal::None,
13497                )
13498            });
13499        })
13500    }
13501
13502    pub fn delete_to_previous_word_start(
13503        &mut self,
13504        action: &DeleteToPreviousWordStart,
13505        window: &mut Window,
13506        cx: &mut Context<Self>,
13507    ) {
13508        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13509        self.transact(window, cx, |this, window, cx| {
13510            this.select_autoclose_pair(window, cx);
13511            this.change_selections(Default::default(), window, cx, |s| {
13512                s.move_with(|map, selection| {
13513                    if selection.is_empty() {
13514                        let mut cursor = if action.ignore_newlines {
13515                            movement::previous_word_start(map, selection.head())
13516                        } else {
13517                            movement::previous_word_start_or_newline(map, selection.head())
13518                        };
13519                        cursor = movement::adjust_greedy_deletion(
13520                            map,
13521                            selection.head(),
13522                            cursor,
13523                            action.ignore_brackets,
13524                        );
13525                        selection.set_head(cursor, SelectionGoal::None);
13526                    }
13527                });
13528            });
13529            this.insert("", window, cx);
13530        });
13531    }
13532
13533    pub fn delete_to_previous_subword_start(
13534        &mut self,
13535        _: &DeleteToPreviousSubwordStart,
13536        window: &mut Window,
13537        cx: &mut Context<Self>,
13538    ) {
13539        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13540        self.transact(window, cx, |this, window, cx| {
13541            this.select_autoclose_pair(window, cx);
13542            this.change_selections(Default::default(), window, cx, |s| {
13543                s.move_with(|map, selection| {
13544                    if selection.is_empty() {
13545                        let mut cursor = movement::previous_subword_start(map, selection.head());
13546                        cursor =
13547                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13548                        selection.set_head(cursor, SelectionGoal::None);
13549                    }
13550                });
13551            });
13552            this.insert("", window, cx);
13553        });
13554    }
13555
13556    pub fn move_to_next_word_end(
13557        &mut self,
13558        _: &MoveToNextWordEnd,
13559        window: &mut Window,
13560        cx: &mut Context<Self>,
13561    ) {
13562        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13563        self.change_selections(Default::default(), window, cx, |s| {
13564            s.move_cursors_with(|map, head, _| {
13565                (movement::next_word_end(map, head), SelectionGoal::None)
13566            });
13567        })
13568    }
13569
13570    pub fn move_to_next_subword_end(
13571        &mut self,
13572        _: &MoveToNextSubwordEnd,
13573        window: &mut Window,
13574        cx: &mut Context<Self>,
13575    ) {
13576        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13577        self.change_selections(Default::default(), window, cx, |s| {
13578            s.move_cursors_with(|map, head, _| {
13579                (movement::next_subword_end(map, head), SelectionGoal::None)
13580            });
13581        })
13582    }
13583
13584    pub fn select_to_next_word_end(
13585        &mut self,
13586        _: &SelectToNextWordEnd,
13587        window: &mut Window,
13588        cx: &mut Context<Self>,
13589    ) {
13590        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13591        self.change_selections(Default::default(), window, cx, |s| {
13592            s.move_heads_with(|map, head, _| {
13593                (movement::next_word_end(map, head), SelectionGoal::None)
13594            });
13595        })
13596    }
13597
13598    pub fn select_to_next_subword_end(
13599        &mut self,
13600        _: &SelectToNextSubwordEnd,
13601        window: &mut Window,
13602        cx: &mut Context<Self>,
13603    ) {
13604        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13605        self.change_selections(Default::default(), window, cx, |s| {
13606            s.move_heads_with(|map, head, _| {
13607                (movement::next_subword_end(map, head), SelectionGoal::None)
13608            });
13609        })
13610    }
13611
13612    pub fn delete_to_next_word_end(
13613        &mut self,
13614        action: &DeleteToNextWordEnd,
13615        window: &mut Window,
13616        cx: &mut Context<Self>,
13617    ) {
13618        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13619        self.transact(window, cx, |this, window, cx| {
13620            this.change_selections(Default::default(), window, cx, |s| {
13621                s.move_with(|map, selection| {
13622                    if selection.is_empty() {
13623                        let mut cursor = if action.ignore_newlines {
13624                            movement::next_word_end(map, selection.head())
13625                        } else {
13626                            movement::next_word_end_or_newline(map, selection.head())
13627                        };
13628                        cursor = movement::adjust_greedy_deletion(
13629                            map,
13630                            selection.head(),
13631                            cursor,
13632                            action.ignore_brackets,
13633                        );
13634                        selection.set_head(cursor, SelectionGoal::None);
13635                    }
13636                });
13637            });
13638            this.insert("", window, cx);
13639        });
13640    }
13641
13642    pub fn delete_to_next_subword_end(
13643        &mut self,
13644        _: &DeleteToNextSubwordEnd,
13645        window: &mut Window,
13646        cx: &mut Context<Self>,
13647    ) {
13648        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13649        self.transact(window, cx, |this, window, cx| {
13650            this.change_selections(Default::default(), window, cx, |s| {
13651                s.move_with(|map, selection| {
13652                    if selection.is_empty() {
13653                        let mut cursor = movement::next_subword_end(map, selection.head());
13654                        cursor =
13655                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13656                        selection.set_head(cursor, SelectionGoal::None);
13657                    }
13658                });
13659            });
13660            this.insert("", window, cx);
13661        });
13662    }
13663
13664    pub fn move_to_beginning_of_line(
13665        &mut self,
13666        action: &MoveToBeginningOfLine,
13667        window: &mut Window,
13668        cx: &mut Context<Self>,
13669    ) {
13670        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13671        self.change_selections(Default::default(), window, cx, |s| {
13672            s.move_cursors_with(|map, head, _| {
13673                (
13674                    movement::indented_line_beginning(
13675                        map,
13676                        head,
13677                        action.stop_at_soft_wraps,
13678                        action.stop_at_indent,
13679                    ),
13680                    SelectionGoal::None,
13681                )
13682            });
13683        })
13684    }
13685
13686    pub fn select_to_beginning_of_line(
13687        &mut self,
13688        action: &SelectToBeginningOfLine,
13689        window: &mut Window,
13690        cx: &mut Context<Self>,
13691    ) {
13692        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13693        self.change_selections(Default::default(), window, cx, |s| {
13694            s.move_heads_with(|map, head, _| {
13695                (
13696                    movement::indented_line_beginning(
13697                        map,
13698                        head,
13699                        action.stop_at_soft_wraps,
13700                        action.stop_at_indent,
13701                    ),
13702                    SelectionGoal::None,
13703                )
13704            });
13705        });
13706    }
13707
13708    pub fn delete_to_beginning_of_line(
13709        &mut self,
13710        action: &DeleteToBeginningOfLine,
13711        window: &mut Window,
13712        cx: &mut Context<Self>,
13713    ) {
13714        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13715        self.transact(window, cx, |this, window, cx| {
13716            this.change_selections(Default::default(), window, cx, |s| {
13717                s.move_with(|_, selection| {
13718                    selection.reversed = true;
13719                });
13720            });
13721
13722            this.select_to_beginning_of_line(
13723                &SelectToBeginningOfLine {
13724                    stop_at_soft_wraps: false,
13725                    stop_at_indent: action.stop_at_indent,
13726                },
13727                window,
13728                cx,
13729            );
13730            this.backspace(&Backspace, window, cx);
13731        });
13732    }
13733
13734    pub fn move_to_end_of_line(
13735        &mut self,
13736        action: &MoveToEndOfLine,
13737        window: &mut Window,
13738        cx: &mut Context<Self>,
13739    ) {
13740        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13741        self.change_selections(Default::default(), window, cx, |s| {
13742            s.move_cursors_with(|map, head, _| {
13743                (
13744                    movement::line_end(map, head, action.stop_at_soft_wraps),
13745                    SelectionGoal::None,
13746                )
13747            });
13748        })
13749    }
13750
13751    pub fn select_to_end_of_line(
13752        &mut self,
13753        action: &SelectToEndOfLine,
13754        window: &mut Window,
13755        cx: &mut Context<Self>,
13756    ) {
13757        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13758        self.change_selections(Default::default(), window, cx, |s| {
13759            s.move_heads_with(|map, head, _| {
13760                (
13761                    movement::line_end(map, head, action.stop_at_soft_wraps),
13762                    SelectionGoal::None,
13763                )
13764            });
13765        })
13766    }
13767
13768    pub fn delete_to_end_of_line(
13769        &mut self,
13770        _: &DeleteToEndOfLine,
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.select_to_end_of_line(
13777                &SelectToEndOfLine {
13778                    stop_at_soft_wraps: false,
13779                },
13780                window,
13781                cx,
13782            );
13783            this.delete(&Delete, window, cx);
13784        });
13785    }
13786
13787    pub fn cut_to_end_of_line(
13788        &mut self,
13789        action: &CutToEndOfLine,
13790        window: &mut Window,
13791        cx: &mut Context<Self>,
13792    ) {
13793        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13794        self.transact(window, cx, |this, window, cx| {
13795            this.select_to_end_of_line(
13796                &SelectToEndOfLine {
13797                    stop_at_soft_wraps: false,
13798                },
13799                window,
13800                cx,
13801            );
13802            if !action.stop_at_newlines {
13803                this.change_selections(Default::default(), window, cx, |s| {
13804                    s.move_with(|_, sel| {
13805                        if sel.is_empty() {
13806                            sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
13807                        }
13808                    });
13809                });
13810            }
13811            this.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13812            let item = this.cut_common(false, window, cx);
13813            cx.write_to_clipboard(item);
13814        });
13815    }
13816
13817    pub fn move_to_start_of_paragraph(
13818        &mut self,
13819        _: &MoveToStartOfParagraph,
13820        window: &mut Window,
13821        cx: &mut Context<Self>,
13822    ) {
13823        if matches!(self.mode, EditorMode::SingleLine) {
13824            cx.propagate();
13825            return;
13826        }
13827        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13828        self.change_selections(Default::default(), window, cx, |s| {
13829            s.move_with(|map, selection| {
13830                selection.collapse_to(
13831                    movement::start_of_paragraph(map, selection.head(), 1),
13832                    SelectionGoal::None,
13833                )
13834            });
13835        })
13836    }
13837
13838    pub fn move_to_end_of_paragraph(
13839        &mut self,
13840        _: &MoveToEndOfParagraph,
13841        window: &mut Window,
13842        cx: &mut Context<Self>,
13843    ) {
13844        if matches!(self.mode, EditorMode::SingleLine) {
13845            cx.propagate();
13846            return;
13847        }
13848        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13849        self.change_selections(Default::default(), window, cx, |s| {
13850            s.move_with(|map, selection| {
13851                selection.collapse_to(
13852                    movement::end_of_paragraph(map, selection.head(), 1),
13853                    SelectionGoal::None,
13854                )
13855            });
13856        })
13857    }
13858
13859    pub fn select_to_start_of_paragraph(
13860        &mut self,
13861        _: &SelectToStartOfParagraph,
13862        window: &mut Window,
13863        cx: &mut Context<Self>,
13864    ) {
13865        if matches!(self.mode, EditorMode::SingleLine) {
13866            cx.propagate();
13867            return;
13868        }
13869        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13870        self.change_selections(Default::default(), window, cx, |s| {
13871            s.move_heads_with(|map, head, _| {
13872                (
13873                    movement::start_of_paragraph(map, head, 1),
13874                    SelectionGoal::None,
13875                )
13876            });
13877        })
13878    }
13879
13880    pub fn select_to_end_of_paragraph(
13881        &mut self,
13882        _: &SelectToEndOfParagraph,
13883        window: &mut Window,
13884        cx: &mut Context<Self>,
13885    ) {
13886        if matches!(self.mode, EditorMode::SingleLine) {
13887            cx.propagate();
13888            return;
13889        }
13890        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13891        self.change_selections(Default::default(), window, cx, |s| {
13892            s.move_heads_with(|map, head, _| {
13893                (
13894                    movement::end_of_paragraph(map, head, 1),
13895                    SelectionGoal::None,
13896                )
13897            });
13898        })
13899    }
13900
13901    pub fn move_to_start_of_excerpt(
13902        &mut self,
13903        _: &MoveToStartOfExcerpt,
13904        window: &mut Window,
13905        cx: &mut Context<Self>,
13906    ) {
13907        if matches!(self.mode, EditorMode::SingleLine) {
13908            cx.propagate();
13909            return;
13910        }
13911        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13912        self.change_selections(Default::default(), window, cx, |s| {
13913            s.move_with(|map, selection| {
13914                selection.collapse_to(
13915                    movement::start_of_excerpt(
13916                        map,
13917                        selection.head(),
13918                        workspace::searchable::Direction::Prev,
13919                    ),
13920                    SelectionGoal::None,
13921                )
13922            });
13923        })
13924    }
13925
13926    pub fn move_to_start_of_next_excerpt(
13927        &mut self,
13928        _: &MoveToStartOfNextExcerpt,
13929        window: &mut Window,
13930        cx: &mut Context<Self>,
13931    ) {
13932        if matches!(self.mode, EditorMode::SingleLine) {
13933            cx.propagate();
13934            return;
13935        }
13936
13937        self.change_selections(Default::default(), window, cx, |s| {
13938            s.move_with(|map, selection| {
13939                selection.collapse_to(
13940                    movement::start_of_excerpt(
13941                        map,
13942                        selection.head(),
13943                        workspace::searchable::Direction::Next,
13944                    ),
13945                    SelectionGoal::None,
13946                )
13947            });
13948        })
13949    }
13950
13951    pub fn move_to_end_of_excerpt(
13952        &mut self,
13953        _: &MoveToEndOfExcerpt,
13954        window: &mut Window,
13955        cx: &mut Context<Self>,
13956    ) {
13957        if matches!(self.mode, EditorMode::SingleLine) {
13958            cx.propagate();
13959            return;
13960        }
13961        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13962        self.change_selections(Default::default(), window, cx, |s| {
13963            s.move_with(|map, selection| {
13964                selection.collapse_to(
13965                    movement::end_of_excerpt(
13966                        map,
13967                        selection.head(),
13968                        workspace::searchable::Direction::Next,
13969                    ),
13970                    SelectionGoal::None,
13971                )
13972            });
13973        })
13974    }
13975
13976    pub fn move_to_end_of_previous_excerpt(
13977        &mut self,
13978        _: &MoveToEndOfPreviousExcerpt,
13979        window: &mut Window,
13980        cx: &mut Context<Self>,
13981    ) {
13982        if matches!(self.mode, EditorMode::SingleLine) {
13983            cx.propagate();
13984            return;
13985        }
13986        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13987        self.change_selections(Default::default(), window, cx, |s| {
13988            s.move_with(|map, selection| {
13989                selection.collapse_to(
13990                    movement::end_of_excerpt(
13991                        map,
13992                        selection.head(),
13993                        workspace::searchable::Direction::Prev,
13994                    ),
13995                    SelectionGoal::None,
13996                )
13997            });
13998        })
13999    }
14000
14001    pub fn select_to_start_of_excerpt(
14002        &mut self,
14003        _: &SelectToStartOfExcerpt,
14004        window: &mut Window,
14005        cx: &mut Context<Self>,
14006    ) {
14007        if matches!(self.mode, EditorMode::SingleLine) {
14008            cx.propagate();
14009            return;
14010        }
14011        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14012        self.change_selections(Default::default(), window, cx, |s| {
14013            s.move_heads_with(|map, head, _| {
14014                (
14015                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
14016                    SelectionGoal::None,
14017                )
14018            });
14019        })
14020    }
14021
14022    pub fn select_to_start_of_next_excerpt(
14023        &mut self,
14024        _: &SelectToStartOfNextExcerpt,
14025        window: &mut Window,
14026        cx: &mut Context<Self>,
14027    ) {
14028        if matches!(self.mode, EditorMode::SingleLine) {
14029            cx.propagate();
14030            return;
14031        }
14032        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14033        self.change_selections(Default::default(), window, cx, |s| {
14034            s.move_heads_with(|map, head, _| {
14035                (
14036                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
14037                    SelectionGoal::None,
14038                )
14039            });
14040        })
14041    }
14042
14043    pub fn select_to_end_of_excerpt(
14044        &mut self,
14045        _: &SelectToEndOfExcerpt,
14046        window: &mut Window,
14047        cx: &mut Context<Self>,
14048    ) {
14049        if matches!(self.mode, EditorMode::SingleLine) {
14050            cx.propagate();
14051            return;
14052        }
14053        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14054        self.change_selections(Default::default(), window, cx, |s| {
14055            s.move_heads_with(|map, head, _| {
14056                (
14057                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
14058                    SelectionGoal::None,
14059                )
14060            });
14061        })
14062    }
14063
14064    pub fn select_to_end_of_previous_excerpt(
14065        &mut self,
14066        _: &SelectToEndOfPreviousExcerpt,
14067        window: &mut Window,
14068        cx: &mut Context<Self>,
14069    ) {
14070        if matches!(self.mode, EditorMode::SingleLine) {
14071            cx.propagate();
14072            return;
14073        }
14074        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14075        self.change_selections(Default::default(), window, cx, |s| {
14076            s.move_heads_with(|map, head, _| {
14077                (
14078                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
14079                    SelectionGoal::None,
14080                )
14081            });
14082        })
14083    }
14084
14085    pub fn move_to_beginning(
14086        &mut self,
14087        _: &MoveToBeginning,
14088        window: &mut Window,
14089        cx: &mut Context<Self>,
14090    ) {
14091        if matches!(self.mode, EditorMode::SingleLine) {
14092            cx.propagate();
14093            return;
14094        }
14095        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14096        self.change_selections(Default::default(), window, cx, |s| {
14097            s.select_ranges(vec![0..0]);
14098        });
14099    }
14100
14101    pub fn select_to_beginning(
14102        &mut self,
14103        _: &SelectToBeginning,
14104        window: &mut Window,
14105        cx: &mut Context<Self>,
14106    ) {
14107        let mut selection = self.selections.last::<Point>(&self.display_snapshot(cx));
14108        selection.set_head(Point::zero(), SelectionGoal::None);
14109        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14110        self.change_selections(Default::default(), window, cx, |s| {
14111            s.select(vec![selection]);
14112        });
14113    }
14114
14115    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
14116        if matches!(self.mode, EditorMode::SingleLine) {
14117            cx.propagate();
14118            return;
14119        }
14120        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14121        let cursor = self.buffer.read(cx).read(cx).len();
14122        self.change_selections(Default::default(), window, cx, |s| {
14123            s.select_ranges(vec![cursor..cursor])
14124        });
14125    }
14126
14127    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
14128        self.nav_history = nav_history;
14129    }
14130
14131    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
14132        self.nav_history.as_ref()
14133    }
14134
14135    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
14136        self.push_to_nav_history(
14137            self.selections.newest_anchor().head(),
14138            None,
14139            false,
14140            true,
14141            cx,
14142        );
14143    }
14144
14145    fn push_to_nav_history(
14146        &mut self,
14147        cursor_anchor: Anchor,
14148        new_position: Option<Point>,
14149        is_deactivate: bool,
14150        always: bool,
14151        cx: &mut Context<Self>,
14152    ) {
14153        if let Some(nav_history) = self.nav_history.as_mut() {
14154            let buffer = self.buffer.read(cx).read(cx);
14155            let cursor_position = cursor_anchor.to_point(&buffer);
14156            let scroll_state = self.scroll_manager.anchor();
14157            let scroll_top_row = scroll_state.top_row(&buffer);
14158            drop(buffer);
14159
14160            if let Some(new_position) = new_position {
14161                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
14162                if row_delta == 0 || (row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA && !always) {
14163                    return;
14164                }
14165            }
14166
14167            nav_history.push(
14168                Some(NavigationData {
14169                    cursor_anchor,
14170                    cursor_position,
14171                    scroll_anchor: scroll_state,
14172                    scroll_top_row,
14173                }),
14174                cx,
14175            );
14176            cx.emit(EditorEvent::PushedToNavHistory {
14177                anchor: cursor_anchor,
14178                is_deactivate,
14179            })
14180        }
14181    }
14182
14183    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
14184        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14185        let buffer = self.buffer.read(cx).snapshot(cx);
14186        let mut selection = self.selections.first::<usize>(&self.display_snapshot(cx));
14187        selection.set_head(buffer.len(), SelectionGoal::None);
14188        self.change_selections(Default::default(), window, cx, |s| {
14189            s.select(vec![selection]);
14190        });
14191    }
14192
14193    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
14194        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14195        let end = self.buffer.read(cx).read(cx).len();
14196        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14197            s.select_ranges(vec![0..end]);
14198        });
14199    }
14200
14201    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
14202        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14203        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14204        let mut selections = self.selections.all::<Point>(&display_map);
14205        let max_point = display_map.buffer_snapshot().max_point();
14206        for selection in &mut selections {
14207            let rows = selection.spanned_rows(true, &display_map);
14208            selection.start = Point::new(rows.start.0, 0);
14209            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
14210            selection.reversed = false;
14211        }
14212        self.change_selections(Default::default(), window, cx, |s| {
14213            s.select(selections);
14214        });
14215    }
14216
14217    pub fn split_selection_into_lines(
14218        &mut self,
14219        action: &SplitSelectionIntoLines,
14220        window: &mut Window,
14221        cx: &mut Context<Self>,
14222    ) {
14223        let selections = self
14224            .selections
14225            .all::<Point>(&self.display_snapshot(cx))
14226            .into_iter()
14227            .map(|selection| selection.start..selection.end)
14228            .collect::<Vec<_>>();
14229        self.unfold_ranges(&selections, true, true, cx);
14230
14231        let mut new_selection_ranges = Vec::new();
14232        {
14233            let buffer = self.buffer.read(cx).read(cx);
14234            for selection in selections {
14235                for row in selection.start.row..selection.end.row {
14236                    let line_start = Point::new(row, 0);
14237                    let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
14238
14239                    if action.keep_selections {
14240                        // Keep the selection range for each line
14241                        let selection_start = if row == selection.start.row {
14242                            selection.start
14243                        } else {
14244                            line_start
14245                        };
14246                        new_selection_ranges.push(selection_start..line_end);
14247                    } else {
14248                        // Collapse to cursor at end of line
14249                        new_selection_ranges.push(line_end..line_end);
14250                    }
14251                }
14252
14253                let is_multiline_selection = selection.start.row != selection.end.row;
14254                // Don't insert last one if it's a multi-line selection ending at the start of a line,
14255                // so this action feels more ergonomic when paired with other selection operations
14256                let should_skip_last = is_multiline_selection && selection.end.column == 0;
14257                if !should_skip_last {
14258                    if action.keep_selections {
14259                        if is_multiline_selection {
14260                            let line_start = Point::new(selection.end.row, 0);
14261                            new_selection_ranges.push(line_start..selection.end);
14262                        } else {
14263                            new_selection_ranges.push(selection.start..selection.end);
14264                        }
14265                    } else {
14266                        new_selection_ranges.push(selection.end..selection.end);
14267                    }
14268                }
14269            }
14270        }
14271        self.change_selections(Default::default(), window, cx, |s| {
14272            s.select_ranges(new_selection_ranges);
14273        });
14274    }
14275
14276    pub fn add_selection_above(
14277        &mut self,
14278        action: &AddSelectionAbove,
14279        window: &mut Window,
14280        cx: &mut Context<Self>,
14281    ) {
14282        self.add_selection(true, action.skip_soft_wrap, window, cx);
14283    }
14284
14285    pub fn add_selection_below(
14286        &mut self,
14287        action: &AddSelectionBelow,
14288        window: &mut Window,
14289        cx: &mut Context<Self>,
14290    ) {
14291        self.add_selection(false, action.skip_soft_wrap, window, cx);
14292    }
14293
14294    fn add_selection(
14295        &mut self,
14296        above: bool,
14297        skip_soft_wrap: bool,
14298        window: &mut Window,
14299        cx: &mut Context<Self>,
14300    ) {
14301        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14302
14303        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14304        let all_selections = self.selections.all::<Point>(&display_map);
14305        let text_layout_details = self.text_layout_details(window);
14306
14307        let (mut columnar_selections, new_selections_to_columnarize) = {
14308            if let Some(state) = self.add_selections_state.as_ref() {
14309                let columnar_selection_ids: HashSet<_> = state
14310                    .groups
14311                    .iter()
14312                    .flat_map(|group| group.stack.iter())
14313                    .copied()
14314                    .collect();
14315
14316                all_selections
14317                    .into_iter()
14318                    .partition(|s| columnar_selection_ids.contains(&s.id))
14319            } else {
14320                (Vec::new(), all_selections)
14321            }
14322        };
14323
14324        let mut state = self
14325            .add_selections_state
14326            .take()
14327            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
14328
14329        for selection in new_selections_to_columnarize {
14330            let range = selection.display_range(&display_map).sorted();
14331            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
14332            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
14333            let positions = start_x.min(end_x)..start_x.max(end_x);
14334            let mut stack = Vec::new();
14335            for row in range.start.row().0..=range.end.row().0 {
14336                if let Some(selection) = self.selections.build_columnar_selection(
14337                    &display_map,
14338                    DisplayRow(row),
14339                    &positions,
14340                    selection.reversed,
14341                    &text_layout_details,
14342                ) {
14343                    stack.push(selection.id);
14344                    columnar_selections.push(selection);
14345                }
14346            }
14347            if !stack.is_empty() {
14348                if above {
14349                    stack.reverse();
14350                }
14351                state.groups.push(AddSelectionsGroup { above, stack });
14352            }
14353        }
14354
14355        let mut final_selections = Vec::new();
14356        let end_row = if above {
14357            DisplayRow(0)
14358        } else {
14359            display_map.max_point().row()
14360        };
14361
14362        let mut last_added_item_per_group = HashMap::default();
14363        for group in state.groups.iter_mut() {
14364            if let Some(last_id) = group.stack.last() {
14365                last_added_item_per_group.insert(*last_id, group);
14366            }
14367        }
14368
14369        for selection in columnar_selections {
14370            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
14371                if above == group.above {
14372                    let range = selection.display_range(&display_map).sorted();
14373                    debug_assert_eq!(range.start.row(), range.end.row());
14374                    let mut row = range.start.row();
14375                    let positions =
14376                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
14377                            Pixels::from(start)..Pixels::from(end)
14378                        } else {
14379                            let start_x =
14380                                display_map.x_for_display_point(range.start, &text_layout_details);
14381                            let end_x =
14382                                display_map.x_for_display_point(range.end, &text_layout_details);
14383                            start_x.min(end_x)..start_x.max(end_x)
14384                        };
14385
14386                    let mut maybe_new_selection = None;
14387                    let direction = if above { -1 } else { 1 };
14388
14389                    while row != end_row {
14390                        if skip_soft_wrap {
14391                            row = display_map
14392                                .start_of_relative_buffer_row(DisplayPoint::new(row, 0), direction)
14393                                .row();
14394                        } else if above {
14395                            row.0 -= 1;
14396                        } else {
14397                            row.0 += 1;
14398                        }
14399
14400                        if let Some(new_selection) = self.selections.build_columnar_selection(
14401                            &display_map,
14402                            row,
14403                            &positions,
14404                            selection.reversed,
14405                            &text_layout_details,
14406                        ) {
14407                            maybe_new_selection = Some(new_selection);
14408                            break;
14409                        }
14410                    }
14411
14412                    if let Some(new_selection) = maybe_new_selection {
14413                        group.stack.push(new_selection.id);
14414                        if above {
14415                            final_selections.push(new_selection);
14416                            final_selections.push(selection);
14417                        } else {
14418                            final_selections.push(selection);
14419                            final_selections.push(new_selection);
14420                        }
14421                    } else {
14422                        final_selections.push(selection);
14423                    }
14424                } else {
14425                    group.stack.pop();
14426                }
14427            } else {
14428                final_selections.push(selection);
14429            }
14430        }
14431
14432        self.change_selections(Default::default(), window, cx, |s| {
14433            s.select(final_selections);
14434        });
14435
14436        let final_selection_ids: HashSet<_> = self
14437            .selections
14438            .all::<Point>(&display_map)
14439            .iter()
14440            .map(|s| s.id)
14441            .collect();
14442        state.groups.retain_mut(|group| {
14443            // selections might get merged above so we remove invalid items from stacks
14444            group.stack.retain(|id| final_selection_ids.contains(id));
14445
14446            // single selection in stack can be treated as initial state
14447            group.stack.len() > 1
14448        });
14449
14450        if !state.groups.is_empty() {
14451            self.add_selections_state = Some(state);
14452        }
14453    }
14454
14455    fn select_match_ranges(
14456        &mut self,
14457        range: Range<usize>,
14458        reversed: bool,
14459        replace_newest: bool,
14460        auto_scroll: Option<Autoscroll>,
14461        window: &mut Window,
14462        cx: &mut Context<Editor>,
14463    ) {
14464        self.unfold_ranges(
14465            std::slice::from_ref(&range),
14466            false,
14467            auto_scroll.is_some(),
14468            cx,
14469        );
14470        let effects = if let Some(scroll) = auto_scroll {
14471            SelectionEffects::scroll(scroll)
14472        } else {
14473            SelectionEffects::no_scroll()
14474        };
14475        self.change_selections(effects, window, cx, |s| {
14476            if replace_newest {
14477                s.delete(s.newest_anchor().id);
14478            }
14479            if reversed {
14480                s.insert_range(range.end..range.start);
14481            } else {
14482                s.insert_range(range);
14483            }
14484        });
14485    }
14486
14487    pub fn select_next_match_internal(
14488        &mut self,
14489        display_map: &DisplaySnapshot,
14490        replace_newest: bool,
14491        autoscroll: Option<Autoscroll>,
14492        window: &mut Window,
14493        cx: &mut Context<Self>,
14494    ) -> Result<()> {
14495        let buffer = display_map.buffer_snapshot();
14496        let mut selections = self.selections.all::<usize>(&display_map);
14497        if let Some(mut select_next_state) = self.select_next_state.take() {
14498            let query = &select_next_state.query;
14499            if !select_next_state.done {
14500                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14501                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14502                let mut next_selected_range = None;
14503
14504                let bytes_after_last_selection =
14505                    buffer.bytes_in_range(last_selection.end..buffer.len());
14506                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
14507                let query_matches = query
14508                    .stream_find_iter(bytes_after_last_selection)
14509                    .map(|result| (last_selection.end, result))
14510                    .chain(
14511                        query
14512                            .stream_find_iter(bytes_before_first_selection)
14513                            .map(|result| (0, result)),
14514                    );
14515
14516                for (start_offset, query_match) in query_matches {
14517                    let query_match = query_match.unwrap(); // can only fail due to I/O
14518                    let offset_range =
14519                        start_offset + query_match.start()..start_offset + query_match.end();
14520
14521                    if !select_next_state.wordwise
14522                        || (!buffer.is_inside_word(offset_range.start, None)
14523                            && !buffer.is_inside_word(offset_range.end, None))
14524                    {
14525                        let idx = selections
14526                            .partition_point(|selection| selection.end <= offset_range.start);
14527                        let overlaps = selections
14528                            .get(idx)
14529                            .map_or(false, |selection| selection.start < offset_range.end);
14530
14531                        if !overlaps {
14532                            next_selected_range = Some(offset_range);
14533                            break;
14534                        }
14535                    }
14536                }
14537
14538                if let Some(next_selected_range) = next_selected_range {
14539                    self.select_match_ranges(
14540                        next_selected_range,
14541                        last_selection.reversed,
14542                        replace_newest,
14543                        autoscroll,
14544                        window,
14545                        cx,
14546                    );
14547                } else {
14548                    select_next_state.done = true;
14549                }
14550            }
14551
14552            self.select_next_state = Some(select_next_state);
14553        } else {
14554            let mut only_carets = true;
14555            let mut same_text_selected = true;
14556            let mut selected_text = None;
14557
14558            let mut selections_iter = selections.iter().peekable();
14559            while let Some(selection) = selections_iter.next() {
14560                if selection.start != selection.end {
14561                    only_carets = false;
14562                }
14563
14564                if same_text_selected {
14565                    if selected_text.is_none() {
14566                        selected_text =
14567                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14568                    }
14569
14570                    if let Some(next_selection) = selections_iter.peek() {
14571                        if next_selection.range().len() == selection.range().len() {
14572                            let next_selected_text = buffer
14573                                .text_for_range(next_selection.range())
14574                                .collect::<String>();
14575                            if Some(next_selected_text) != selected_text {
14576                                same_text_selected = false;
14577                                selected_text = None;
14578                            }
14579                        } else {
14580                            same_text_selected = false;
14581                            selected_text = None;
14582                        }
14583                    }
14584                }
14585            }
14586
14587            if only_carets {
14588                for selection in &mut selections {
14589                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
14590                    selection.start = word_range.start;
14591                    selection.end = word_range.end;
14592                    selection.goal = SelectionGoal::None;
14593                    selection.reversed = false;
14594                    self.select_match_ranges(
14595                        selection.start..selection.end,
14596                        selection.reversed,
14597                        replace_newest,
14598                        autoscroll,
14599                        window,
14600                        cx,
14601                    );
14602                }
14603
14604                if selections.len() == 1 {
14605                    let selection = selections
14606                        .last()
14607                        .expect("ensured that there's only one selection");
14608                    let query = buffer
14609                        .text_for_range(selection.start..selection.end)
14610                        .collect::<String>();
14611                    let is_empty = query.is_empty();
14612                    let select_state = SelectNextState {
14613                        query: AhoCorasick::new(&[query])?,
14614                        wordwise: true,
14615                        done: is_empty,
14616                    };
14617                    self.select_next_state = Some(select_state);
14618                } else {
14619                    self.select_next_state = None;
14620                }
14621            } else if let Some(selected_text) = selected_text {
14622                self.select_next_state = Some(SelectNextState {
14623                    query: AhoCorasick::new(&[selected_text])?,
14624                    wordwise: false,
14625                    done: false,
14626                });
14627                self.select_next_match_internal(
14628                    display_map,
14629                    replace_newest,
14630                    autoscroll,
14631                    window,
14632                    cx,
14633                )?;
14634            }
14635        }
14636        Ok(())
14637    }
14638
14639    pub fn select_all_matches(
14640        &mut self,
14641        _action: &SelectAllMatches,
14642        window: &mut Window,
14643        cx: &mut Context<Self>,
14644    ) -> Result<()> {
14645        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14646
14647        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14648
14649        self.select_next_match_internal(&display_map, false, None, window, cx)?;
14650        let Some(select_next_state) = self.select_next_state.as_mut() else {
14651            return Ok(());
14652        };
14653        if select_next_state.done {
14654            return Ok(());
14655        }
14656
14657        let mut new_selections = Vec::new();
14658
14659        let reversed = self.selections.oldest::<usize>(&display_map).reversed;
14660        let buffer = display_map.buffer_snapshot();
14661        let query_matches = select_next_state
14662            .query
14663            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
14664
14665        for query_match in query_matches.into_iter() {
14666            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
14667            let offset_range = if reversed {
14668                query_match.end()..query_match.start()
14669            } else {
14670                query_match.start()..query_match.end()
14671            };
14672
14673            if !select_next_state.wordwise
14674                || (!buffer.is_inside_word(offset_range.start, None)
14675                    && !buffer.is_inside_word(offset_range.end, None))
14676            {
14677                new_selections.push(offset_range.start..offset_range.end);
14678            }
14679        }
14680
14681        select_next_state.done = true;
14682
14683        if new_selections.is_empty() {
14684            log::error!("bug: new_selections is empty in select_all_matches");
14685            return Ok(());
14686        }
14687
14688        self.unfold_ranges(&new_selections.clone(), false, false, cx);
14689        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
14690            selections.select_ranges(new_selections)
14691        });
14692
14693        Ok(())
14694    }
14695
14696    pub fn select_next(
14697        &mut self,
14698        action: &SelectNext,
14699        window: &mut Window,
14700        cx: &mut Context<Self>,
14701    ) -> Result<()> {
14702        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14703        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14704        self.select_next_match_internal(
14705            &display_map,
14706            action.replace_newest,
14707            Some(Autoscroll::newest()),
14708            window,
14709            cx,
14710        )?;
14711        Ok(())
14712    }
14713
14714    pub fn select_previous(
14715        &mut self,
14716        action: &SelectPrevious,
14717        window: &mut Window,
14718        cx: &mut Context<Self>,
14719    ) -> Result<()> {
14720        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14721        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14722        let buffer = display_map.buffer_snapshot();
14723        let mut selections = self.selections.all::<usize>(&display_map);
14724        if let Some(mut select_prev_state) = self.select_prev_state.take() {
14725            let query = &select_prev_state.query;
14726            if !select_prev_state.done {
14727                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14728                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14729                let mut next_selected_range = None;
14730                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
14731                let bytes_before_last_selection =
14732                    buffer.reversed_bytes_in_range(0..last_selection.start);
14733                let bytes_after_first_selection =
14734                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
14735                let query_matches = query
14736                    .stream_find_iter(bytes_before_last_selection)
14737                    .map(|result| (last_selection.start, result))
14738                    .chain(
14739                        query
14740                            .stream_find_iter(bytes_after_first_selection)
14741                            .map(|result| (buffer.len(), result)),
14742                    );
14743                for (end_offset, query_match) in query_matches {
14744                    let query_match = query_match.unwrap(); // can only fail due to I/O
14745                    let offset_range =
14746                        end_offset - query_match.end()..end_offset - query_match.start();
14747
14748                    if !select_prev_state.wordwise
14749                        || (!buffer.is_inside_word(offset_range.start, None)
14750                            && !buffer.is_inside_word(offset_range.end, None))
14751                    {
14752                        next_selected_range = Some(offset_range);
14753                        break;
14754                    }
14755                }
14756
14757                if let Some(next_selected_range) = next_selected_range {
14758                    self.select_match_ranges(
14759                        next_selected_range,
14760                        last_selection.reversed,
14761                        action.replace_newest,
14762                        Some(Autoscroll::newest()),
14763                        window,
14764                        cx,
14765                    );
14766                } else {
14767                    select_prev_state.done = true;
14768                }
14769            }
14770
14771            self.select_prev_state = Some(select_prev_state);
14772        } else {
14773            let mut only_carets = true;
14774            let mut same_text_selected = true;
14775            let mut selected_text = None;
14776
14777            let mut selections_iter = selections.iter().peekable();
14778            while let Some(selection) = selections_iter.next() {
14779                if selection.start != selection.end {
14780                    only_carets = false;
14781                }
14782
14783                if same_text_selected {
14784                    if selected_text.is_none() {
14785                        selected_text =
14786                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14787                    }
14788
14789                    if let Some(next_selection) = selections_iter.peek() {
14790                        if next_selection.range().len() == selection.range().len() {
14791                            let next_selected_text = buffer
14792                                .text_for_range(next_selection.range())
14793                                .collect::<String>();
14794                            if Some(next_selected_text) != selected_text {
14795                                same_text_selected = false;
14796                                selected_text = None;
14797                            }
14798                        } else {
14799                            same_text_selected = false;
14800                            selected_text = None;
14801                        }
14802                    }
14803                }
14804            }
14805
14806            if only_carets {
14807                for selection in &mut selections {
14808                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
14809                    selection.start = word_range.start;
14810                    selection.end = word_range.end;
14811                    selection.goal = SelectionGoal::None;
14812                    selection.reversed = false;
14813                    self.select_match_ranges(
14814                        selection.start..selection.end,
14815                        selection.reversed,
14816                        action.replace_newest,
14817                        Some(Autoscroll::newest()),
14818                        window,
14819                        cx,
14820                    );
14821                }
14822                if selections.len() == 1 {
14823                    let selection = selections
14824                        .last()
14825                        .expect("ensured that there's only one selection");
14826                    let query = buffer
14827                        .text_for_range(selection.start..selection.end)
14828                        .collect::<String>();
14829                    let is_empty = query.is_empty();
14830                    let select_state = SelectNextState {
14831                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
14832                        wordwise: true,
14833                        done: is_empty,
14834                    };
14835                    self.select_prev_state = Some(select_state);
14836                } else {
14837                    self.select_prev_state = None;
14838                }
14839            } else if let Some(selected_text) = selected_text {
14840                self.select_prev_state = Some(SelectNextState {
14841                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
14842                    wordwise: false,
14843                    done: false,
14844                });
14845                self.select_previous(action, window, cx)?;
14846            }
14847        }
14848        Ok(())
14849    }
14850
14851    pub fn find_next_match(
14852        &mut self,
14853        _: &FindNextMatch,
14854        window: &mut Window,
14855        cx: &mut Context<Self>,
14856    ) -> Result<()> {
14857        let selections = self.selections.disjoint_anchors_arc();
14858        match selections.first() {
14859            Some(first) if selections.len() >= 2 => {
14860                self.change_selections(Default::default(), window, cx, |s| {
14861                    s.select_ranges([first.range()]);
14862                });
14863            }
14864            _ => self.select_next(
14865                &SelectNext {
14866                    replace_newest: true,
14867                },
14868                window,
14869                cx,
14870            )?,
14871        }
14872        Ok(())
14873    }
14874
14875    pub fn find_previous_match(
14876        &mut self,
14877        _: &FindPreviousMatch,
14878        window: &mut Window,
14879        cx: &mut Context<Self>,
14880    ) -> Result<()> {
14881        let selections = self.selections.disjoint_anchors_arc();
14882        match selections.last() {
14883            Some(last) if selections.len() >= 2 => {
14884                self.change_selections(Default::default(), window, cx, |s| {
14885                    s.select_ranges([last.range()]);
14886                });
14887            }
14888            _ => self.select_previous(
14889                &SelectPrevious {
14890                    replace_newest: true,
14891                },
14892                window,
14893                cx,
14894            )?,
14895        }
14896        Ok(())
14897    }
14898
14899    pub fn toggle_comments(
14900        &mut self,
14901        action: &ToggleComments,
14902        window: &mut Window,
14903        cx: &mut Context<Self>,
14904    ) {
14905        if self.read_only(cx) {
14906            return;
14907        }
14908        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14909        let text_layout_details = &self.text_layout_details(window);
14910        self.transact(window, cx, |this, window, cx| {
14911            let mut selections = this
14912                .selections
14913                .all::<MultiBufferPoint>(&this.display_snapshot(cx));
14914            let mut edits = Vec::new();
14915            let mut selection_edit_ranges = Vec::new();
14916            let mut last_toggled_row = None;
14917            let snapshot = this.buffer.read(cx).read(cx);
14918            let empty_str: Arc<str> = Arc::default();
14919            let mut suffixes_inserted = Vec::new();
14920            let ignore_indent = action.ignore_indent;
14921
14922            fn comment_prefix_range(
14923                snapshot: &MultiBufferSnapshot,
14924                row: MultiBufferRow,
14925                comment_prefix: &str,
14926                comment_prefix_whitespace: &str,
14927                ignore_indent: bool,
14928            ) -> Range<Point> {
14929                let indent_size = if ignore_indent {
14930                    0
14931                } else {
14932                    snapshot.indent_size_for_line(row).len
14933                };
14934
14935                let start = Point::new(row.0, indent_size);
14936
14937                let mut line_bytes = snapshot
14938                    .bytes_in_range(start..snapshot.max_point())
14939                    .flatten()
14940                    .copied();
14941
14942                // If this line currently begins with the line comment prefix, then record
14943                // the range containing the prefix.
14944                if line_bytes
14945                    .by_ref()
14946                    .take(comment_prefix.len())
14947                    .eq(comment_prefix.bytes())
14948                {
14949                    // Include any whitespace that matches the comment prefix.
14950                    let matching_whitespace_len = line_bytes
14951                        .zip(comment_prefix_whitespace.bytes())
14952                        .take_while(|(a, b)| a == b)
14953                        .count() as u32;
14954                    let end = Point::new(
14955                        start.row,
14956                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
14957                    );
14958                    start..end
14959                } else {
14960                    start..start
14961                }
14962            }
14963
14964            fn comment_suffix_range(
14965                snapshot: &MultiBufferSnapshot,
14966                row: MultiBufferRow,
14967                comment_suffix: &str,
14968                comment_suffix_has_leading_space: bool,
14969            ) -> Range<Point> {
14970                let end = Point::new(row.0, snapshot.line_len(row));
14971                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
14972
14973                let mut line_end_bytes = snapshot
14974                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
14975                    .flatten()
14976                    .copied();
14977
14978                let leading_space_len = if suffix_start_column > 0
14979                    && line_end_bytes.next() == Some(b' ')
14980                    && comment_suffix_has_leading_space
14981                {
14982                    1
14983                } else {
14984                    0
14985                };
14986
14987                // If this line currently begins with the line comment prefix, then record
14988                // the range containing the prefix.
14989                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
14990                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
14991                    start..end
14992                } else {
14993                    end..end
14994                }
14995            }
14996
14997            // TODO: Handle selections that cross excerpts
14998            for selection in &mut selections {
14999                let start_column = snapshot
15000                    .indent_size_for_line(MultiBufferRow(selection.start.row))
15001                    .len;
15002                let language = if let Some(language) =
15003                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
15004                {
15005                    language
15006                } else {
15007                    continue;
15008                };
15009
15010                selection_edit_ranges.clear();
15011
15012                // If multiple selections contain a given row, avoid processing that
15013                // row more than once.
15014                let mut start_row = MultiBufferRow(selection.start.row);
15015                if last_toggled_row == Some(start_row) {
15016                    start_row = start_row.next_row();
15017                }
15018                let end_row =
15019                    if selection.end.row > selection.start.row && selection.end.column == 0 {
15020                        MultiBufferRow(selection.end.row - 1)
15021                    } else {
15022                        MultiBufferRow(selection.end.row)
15023                    };
15024                last_toggled_row = Some(end_row);
15025
15026                if start_row > end_row {
15027                    continue;
15028                }
15029
15030                // If the language has line comments, toggle those.
15031                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
15032
15033                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
15034                if ignore_indent {
15035                    full_comment_prefixes = full_comment_prefixes
15036                        .into_iter()
15037                        .map(|s| Arc::from(s.trim_end()))
15038                        .collect();
15039                }
15040
15041                if !full_comment_prefixes.is_empty() {
15042                    let first_prefix = full_comment_prefixes
15043                        .first()
15044                        .expect("prefixes is non-empty");
15045                    let prefix_trimmed_lengths = full_comment_prefixes
15046                        .iter()
15047                        .map(|p| p.trim_end_matches(' ').len())
15048                        .collect::<SmallVec<[usize; 4]>>();
15049
15050                    let mut all_selection_lines_are_comments = true;
15051
15052                    for row in start_row.0..=end_row.0 {
15053                        let row = MultiBufferRow(row);
15054                        if start_row < end_row && snapshot.is_line_blank(row) {
15055                            continue;
15056                        }
15057
15058                        let prefix_range = full_comment_prefixes
15059                            .iter()
15060                            .zip(prefix_trimmed_lengths.iter().copied())
15061                            .map(|(prefix, trimmed_prefix_len)| {
15062                                comment_prefix_range(
15063                                    snapshot.deref(),
15064                                    row,
15065                                    &prefix[..trimmed_prefix_len],
15066                                    &prefix[trimmed_prefix_len..],
15067                                    ignore_indent,
15068                                )
15069                            })
15070                            .max_by_key(|range| range.end.column - range.start.column)
15071                            .expect("prefixes is non-empty");
15072
15073                        if prefix_range.is_empty() {
15074                            all_selection_lines_are_comments = false;
15075                        }
15076
15077                        selection_edit_ranges.push(prefix_range);
15078                    }
15079
15080                    if all_selection_lines_are_comments {
15081                        edits.extend(
15082                            selection_edit_ranges
15083                                .iter()
15084                                .cloned()
15085                                .map(|range| (range, empty_str.clone())),
15086                        );
15087                    } else {
15088                        let min_column = selection_edit_ranges
15089                            .iter()
15090                            .map(|range| range.start.column)
15091                            .min()
15092                            .unwrap_or(0);
15093                        edits.extend(selection_edit_ranges.iter().map(|range| {
15094                            let position = Point::new(range.start.row, min_column);
15095                            (position..position, first_prefix.clone())
15096                        }));
15097                    }
15098                } else if let Some(BlockCommentConfig {
15099                    start: full_comment_prefix,
15100                    end: comment_suffix,
15101                    ..
15102                }) = language.block_comment()
15103                {
15104                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
15105                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
15106                    let prefix_range = comment_prefix_range(
15107                        snapshot.deref(),
15108                        start_row,
15109                        comment_prefix,
15110                        comment_prefix_whitespace,
15111                        ignore_indent,
15112                    );
15113                    let suffix_range = comment_suffix_range(
15114                        snapshot.deref(),
15115                        end_row,
15116                        comment_suffix.trim_start_matches(' '),
15117                        comment_suffix.starts_with(' '),
15118                    );
15119
15120                    if prefix_range.is_empty() || suffix_range.is_empty() {
15121                        edits.push((
15122                            prefix_range.start..prefix_range.start,
15123                            full_comment_prefix.clone(),
15124                        ));
15125                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
15126                        suffixes_inserted.push((end_row, comment_suffix.len()));
15127                    } else {
15128                        edits.push((prefix_range, empty_str.clone()));
15129                        edits.push((suffix_range, empty_str.clone()));
15130                    }
15131                } else {
15132                    continue;
15133                }
15134            }
15135
15136            drop(snapshot);
15137            this.buffer.update(cx, |buffer, cx| {
15138                buffer.edit(edits, None, cx);
15139            });
15140
15141            // Adjust selections so that they end before any comment suffixes that
15142            // were inserted.
15143            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
15144            let mut selections = this.selections.all::<Point>(&this.display_snapshot(cx));
15145            let snapshot = this.buffer.read(cx).read(cx);
15146            for selection in &mut selections {
15147                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
15148                    match row.cmp(&MultiBufferRow(selection.end.row)) {
15149                        Ordering::Less => {
15150                            suffixes_inserted.next();
15151                            continue;
15152                        }
15153                        Ordering::Greater => break,
15154                        Ordering::Equal => {
15155                            if selection.end.column == snapshot.line_len(row) {
15156                                if selection.is_empty() {
15157                                    selection.start.column -= suffix_len as u32;
15158                                }
15159                                selection.end.column -= suffix_len as u32;
15160                            }
15161                            break;
15162                        }
15163                    }
15164                }
15165            }
15166
15167            drop(snapshot);
15168            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
15169
15170            let selections = this.selections.all::<Point>(&this.display_snapshot(cx));
15171            let selections_on_single_row = selections.windows(2).all(|selections| {
15172                selections[0].start.row == selections[1].start.row
15173                    && selections[0].end.row == selections[1].end.row
15174                    && selections[0].start.row == selections[0].end.row
15175            });
15176            let selections_selecting = selections
15177                .iter()
15178                .any(|selection| selection.start != selection.end);
15179            let advance_downwards = action.advance_downwards
15180                && selections_on_single_row
15181                && !selections_selecting
15182                && !matches!(this.mode, EditorMode::SingleLine);
15183
15184            if advance_downwards {
15185                let snapshot = this.buffer.read(cx).snapshot(cx);
15186
15187                this.change_selections(Default::default(), window, cx, |s| {
15188                    s.move_cursors_with(|display_snapshot, display_point, _| {
15189                        let mut point = display_point.to_point(display_snapshot);
15190                        point.row += 1;
15191                        point = snapshot.clip_point(point, Bias::Left);
15192                        let display_point = point.to_display_point(display_snapshot);
15193                        let goal = SelectionGoal::HorizontalPosition(
15194                            display_snapshot
15195                                .x_for_display_point(display_point, text_layout_details)
15196                                .into(),
15197                        );
15198                        (display_point, goal)
15199                    })
15200                });
15201            }
15202        });
15203    }
15204
15205    pub fn select_enclosing_symbol(
15206        &mut self,
15207        _: &SelectEnclosingSymbol,
15208        window: &mut Window,
15209        cx: &mut Context<Self>,
15210    ) {
15211        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15212
15213        let buffer = self.buffer.read(cx).snapshot(cx);
15214        let old_selections = self
15215            .selections
15216            .all::<usize>(&self.display_snapshot(cx))
15217            .into_boxed_slice();
15218
15219        fn update_selection(
15220            selection: &Selection<usize>,
15221            buffer_snap: &MultiBufferSnapshot,
15222        ) -> Option<Selection<usize>> {
15223            let cursor = selection.head();
15224            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
15225            for symbol in symbols.iter().rev() {
15226                let start = symbol.range.start.to_offset(buffer_snap);
15227                let end = symbol.range.end.to_offset(buffer_snap);
15228                let new_range = start..end;
15229                if start < selection.start || end > selection.end {
15230                    return Some(Selection {
15231                        id: selection.id,
15232                        start: new_range.start,
15233                        end: new_range.end,
15234                        goal: SelectionGoal::None,
15235                        reversed: selection.reversed,
15236                    });
15237                }
15238            }
15239            None
15240        }
15241
15242        let mut selected_larger_symbol = false;
15243        let new_selections = old_selections
15244            .iter()
15245            .map(|selection| match update_selection(selection, &buffer) {
15246                Some(new_selection) => {
15247                    if new_selection.range() != selection.range() {
15248                        selected_larger_symbol = true;
15249                    }
15250                    new_selection
15251                }
15252                None => selection.clone(),
15253            })
15254            .collect::<Vec<_>>();
15255
15256        if selected_larger_symbol {
15257            self.change_selections(Default::default(), window, cx, |s| {
15258                s.select(new_selections);
15259            });
15260        }
15261    }
15262
15263    pub fn select_larger_syntax_node(
15264        &mut self,
15265        _: &SelectLargerSyntaxNode,
15266        window: &mut Window,
15267        cx: &mut Context<Self>,
15268    ) {
15269        let Some(visible_row_count) = self.visible_row_count() else {
15270            return;
15271        };
15272        let old_selections: Box<[_]> = self
15273            .selections
15274            .all::<usize>(&self.display_snapshot(cx))
15275            .into();
15276        if old_selections.is_empty() {
15277            return;
15278        }
15279
15280        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15281
15282        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15283        let buffer = self.buffer.read(cx).snapshot(cx);
15284
15285        let mut selected_larger_node = false;
15286        let mut new_selections = old_selections
15287            .iter()
15288            .map(|selection| {
15289                let old_range = selection.start..selection.end;
15290
15291                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
15292                    // manually select word at selection
15293                    if ["string_content", "inline"].contains(&node.kind()) {
15294                        let (word_range, _) = buffer.surrounding_word(old_range.start, None);
15295                        // ignore if word is already selected
15296                        if !word_range.is_empty() && old_range != word_range {
15297                            let (last_word_range, _) = buffer.surrounding_word(old_range.end, None);
15298                            // only select word if start and end point belongs to same word
15299                            if word_range == last_word_range {
15300                                selected_larger_node = true;
15301                                return Selection {
15302                                    id: selection.id,
15303                                    start: word_range.start,
15304                                    end: word_range.end,
15305                                    goal: SelectionGoal::None,
15306                                    reversed: selection.reversed,
15307                                };
15308                            }
15309                        }
15310                    }
15311                }
15312
15313                let mut new_range = old_range.clone();
15314                while let Some((node, range)) = buffer.syntax_ancestor(new_range.clone()) {
15315                    new_range = range;
15316                    if !node.is_named() {
15317                        continue;
15318                    }
15319                    if !display_map.intersects_fold(new_range.start)
15320                        && !display_map.intersects_fold(new_range.end)
15321                    {
15322                        break;
15323                    }
15324                }
15325
15326                selected_larger_node |= new_range != old_range;
15327                Selection {
15328                    id: selection.id,
15329                    start: new_range.start,
15330                    end: new_range.end,
15331                    goal: SelectionGoal::None,
15332                    reversed: selection.reversed,
15333                }
15334            })
15335            .collect::<Vec<_>>();
15336
15337        if !selected_larger_node {
15338            return; // don't put this call in the history
15339        }
15340
15341        // scroll based on transformation done to the last selection created by the user
15342        let (last_old, last_new) = old_selections
15343            .last()
15344            .zip(new_selections.last().cloned())
15345            .expect("old_selections isn't empty");
15346
15347        // revert selection
15348        let is_selection_reversed = {
15349            let should_newest_selection_be_reversed = last_old.start != last_new.start;
15350            new_selections.last_mut().expect("checked above").reversed =
15351                should_newest_selection_be_reversed;
15352            should_newest_selection_be_reversed
15353        };
15354
15355        if selected_larger_node {
15356            self.select_syntax_node_history.disable_clearing = true;
15357            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15358                s.select(new_selections.clone());
15359            });
15360            self.select_syntax_node_history.disable_clearing = false;
15361        }
15362
15363        let start_row = last_new.start.to_display_point(&display_map).row().0;
15364        let end_row = last_new.end.to_display_point(&display_map).row().0;
15365        let selection_height = end_row - start_row + 1;
15366        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
15367
15368        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
15369        let scroll_behavior = if fits_on_the_screen {
15370            self.request_autoscroll(Autoscroll::fit(), cx);
15371            SelectSyntaxNodeScrollBehavior::FitSelection
15372        } else if is_selection_reversed {
15373            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15374            SelectSyntaxNodeScrollBehavior::CursorTop
15375        } else {
15376            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15377            SelectSyntaxNodeScrollBehavior::CursorBottom
15378        };
15379
15380        self.select_syntax_node_history.push((
15381            old_selections,
15382            scroll_behavior,
15383            is_selection_reversed,
15384        ));
15385    }
15386
15387    pub fn select_smaller_syntax_node(
15388        &mut self,
15389        _: &SelectSmallerSyntaxNode,
15390        window: &mut Window,
15391        cx: &mut Context<Self>,
15392    ) {
15393        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15394
15395        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
15396            self.select_syntax_node_history.pop()
15397        {
15398            if let Some(selection) = selections.last_mut() {
15399                selection.reversed = is_selection_reversed;
15400            }
15401
15402            self.select_syntax_node_history.disable_clearing = true;
15403            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15404                s.select(selections.to_vec());
15405            });
15406            self.select_syntax_node_history.disable_clearing = false;
15407
15408            match scroll_behavior {
15409                SelectSyntaxNodeScrollBehavior::CursorTop => {
15410                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15411                }
15412                SelectSyntaxNodeScrollBehavior::FitSelection => {
15413                    self.request_autoscroll(Autoscroll::fit(), cx);
15414                }
15415                SelectSyntaxNodeScrollBehavior::CursorBottom => {
15416                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15417                }
15418            }
15419        }
15420    }
15421
15422    pub fn unwrap_syntax_node(
15423        &mut self,
15424        _: &UnwrapSyntaxNode,
15425        window: &mut Window,
15426        cx: &mut Context<Self>,
15427    ) {
15428        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15429
15430        let buffer = self.buffer.read(cx).snapshot(cx);
15431        let selections = self
15432            .selections
15433            .all::<usize>(&self.display_snapshot(cx))
15434            .into_iter()
15435            // subtracting the offset requires sorting
15436            .sorted_by_key(|i| i.start);
15437
15438        let full_edits = selections
15439            .into_iter()
15440            .filter_map(|selection| {
15441                let child = if selection.is_empty()
15442                    && let Some((_, ancestor_range)) =
15443                        buffer.syntax_ancestor(selection.start..selection.end)
15444                {
15445                    ancestor_range
15446                } else {
15447                    selection.range()
15448                };
15449
15450                let mut parent = child.clone();
15451                while let Some((_, ancestor_range)) = buffer.syntax_ancestor(parent.clone()) {
15452                    parent = ancestor_range;
15453                    if parent.start < child.start || parent.end > child.end {
15454                        break;
15455                    }
15456                }
15457
15458                if parent == child {
15459                    return None;
15460                }
15461                let text = buffer.text_for_range(child).collect::<String>();
15462                Some((selection.id, parent, text))
15463            })
15464            .collect::<Vec<_>>();
15465        if full_edits.is_empty() {
15466            return;
15467        }
15468
15469        self.transact(window, cx, |this, window, cx| {
15470            this.buffer.update(cx, |buffer, cx| {
15471                buffer.edit(
15472                    full_edits
15473                        .iter()
15474                        .map(|(_, p, t)| (p.clone(), t.clone()))
15475                        .collect::<Vec<_>>(),
15476                    None,
15477                    cx,
15478                );
15479            });
15480            this.change_selections(Default::default(), window, cx, |s| {
15481                let mut offset = 0;
15482                let mut selections = vec![];
15483                for (id, parent, text) in full_edits {
15484                    let start = parent.start - offset;
15485                    offset += parent.len() - text.len();
15486                    selections.push(Selection {
15487                        id,
15488                        start,
15489                        end: start + text.len(),
15490                        reversed: false,
15491                        goal: Default::default(),
15492                    });
15493                }
15494                s.select(selections);
15495            });
15496        });
15497    }
15498
15499    pub fn select_next_syntax_node(
15500        &mut self,
15501        _: &SelectNextSyntaxNode,
15502        window: &mut Window,
15503        cx: &mut Context<Self>,
15504    ) {
15505        let old_selections: Box<[_]> = self
15506            .selections
15507            .all::<usize>(&self.display_snapshot(cx))
15508            .into();
15509        if old_selections.is_empty() {
15510            return;
15511        }
15512
15513        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15514
15515        let buffer = self.buffer.read(cx).snapshot(cx);
15516        let mut selected_sibling = false;
15517
15518        let new_selections = old_selections
15519            .iter()
15520            .map(|selection| {
15521                let old_range = selection.start..selection.end;
15522
15523                if let Some(node) = buffer.syntax_next_sibling(old_range) {
15524                    let new_range = node.byte_range();
15525                    selected_sibling = true;
15526                    Selection {
15527                        id: selection.id,
15528                        start: new_range.start,
15529                        end: new_range.end,
15530                        goal: SelectionGoal::None,
15531                        reversed: selection.reversed,
15532                    }
15533                } else {
15534                    selection.clone()
15535                }
15536            })
15537            .collect::<Vec<_>>();
15538
15539        if selected_sibling {
15540            self.change_selections(
15541                SelectionEffects::scroll(Autoscroll::fit()),
15542                window,
15543                cx,
15544                |s| {
15545                    s.select(new_selections);
15546                },
15547            );
15548        }
15549    }
15550
15551    pub fn select_prev_syntax_node(
15552        &mut self,
15553        _: &SelectPreviousSyntaxNode,
15554        window: &mut Window,
15555        cx: &mut Context<Self>,
15556    ) {
15557        let old_selections: Box<[_]> = self
15558            .selections
15559            .all::<usize>(&self.display_snapshot(cx))
15560            .into();
15561        if old_selections.is_empty() {
15562            return;
15563        }
15564
15565        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15566
15567        let buffer = self.buffer.read(cx).snapshot(cx);
15568        let mut selected_sibling = false;
15569
15570        let new_selections = old_selections
15571            .iter()
15572            .map(|selection| {
15573                let old_range = selection.start..selection.end;
15574
15575                if let Some(node) = buffer.syntax_prev_sibling(old_range) {
15576                    let new_range = node.byte_range();
15577                    selected_sibling = true;
15578                    Selection {
15579                        id: selection.id,
15580                        start: new_range.start,
15581                        end: new_range.end,
15582                        goal: SelectionGoal::None,
15583                        reversed: selection.reversed,
15584                    }
15585                } else {
15586                    selection.clone()
15587                }
15588            })
15589            .collect::<Vec<_>>();
15590
15591        if selected_sibling {
15592            self.change_selections(
15593                SelectionEffects::scroll(Autoscroll::fit()),
15594                window,
15595                cx,
15596                |s| {
15597                    s.select(new_selections);
15598                },
15599            );
15600        }
15601    }
15602
15603    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
15604        if !EditorSettings::get_global(cx).gutter.runnables {
15605            self.clear_tasks();
15606            return Task::ready(());
15607        }
15608        let project = self.project().map(Entity::downgrade);
15609        let task_sources = self.lsp_task_sources(cx);
15610        let multi_buffer = self.buffer.downgrade();
15611        cx.spawn_in(window, async move |editor, cx| {
15612            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
15613            let Some(project) = project.and_then(|p| p.upgrade()) else {
15614                return;
15615            };
15616            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
15617                this.display_map.update(cx, |map, cx| map.snapshot(cx))
15618            }) else {
15619                return;
15620            };
15621
15622            let hide_runnables = project
15623                .update(cx, |project, _| project.is_via_collab())
15624                .unwrap_or(true);
15625            if hide_runnables {
15626                return;
15627            }
15628            let new_rows =
15629                cx.background_spawn({
15630                    let snapshot = display_snapshot.clone();
15631                    async move {
15632                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
15633                    }
15634                })
15635                    .await;
15636            let Ok(lsp_tasks) =
15637                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
15638            else {
15639                return;
15640            };
15641            let lsp_tasks = lsp_tasks.await;
15642
15643            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
15644                lsp_tasks
15645                    .into_iter()
15646                    .flat_map(|(kind, tasks)| {
15647                        tasks.into_iter().filter_map(move |(location, task)| {
15648                            Some((kind.clone(), location?, task))
15649                        })
15650                    })
15651                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
15652                        let buffer = location.target.buffer;
15653                        let buffer_snapshot = buffer.read(cx).snapshot();
15654                        let offset = display_snapshot.buffer_snapshot().excerpts().find_map(
15655                            |(excerpt_id, snapshot, _)| {
15656                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
15657                                    display_snapshot
15658                                        .buffer_snapshot()
15659                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
15660                                } else {
15661                                    None
15662                                }
15663                            },
15664                        );
15665                        if let Some(offset) = offset {
15666                            let task_buffer_range =
15667                                location.target.range.to_point(&buffer_snapshot);
15668                            let context_buffer_range =
15669                                task_buffer_range.to_offset(&buffer_snapshot);
15670                            let context_range = BufferOffset(context_buffer_range.start)
15671                                ..BufferOffset(context_buffer_range.end);
15672
15673                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
15674                                .or_insert_with(|| RunnableTasks {
15675                                    templates: Vec::new(),
15676                                    offset,
15677                                    column: task_buffer_range.start.column,
15678                                    extra_variables: HashMap::default(),
15679                                    context_range,
15680                                })
15681                                .templates
15682                                .push((kind, task.original_task().clone()));
15683                        }
15684
15685                        acc
15686                    })
15687            }) else {
15688                return;
15689            };
15690
15691            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
15692                buffer.language_settings(cx).tasks.prefer_lsp
15693            }) else {
15694                return;
15695            };
15696
15697            let rows = Self::runnable_rows(
15698                project,
15699                display_snapshot,
15700                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
15701                new_rows,
15702                cx.clone(),
15703            )
15704            .await;
15705            editor
15706                .update(cx, |editor, _| {
15707                    editor.clear_tasks();
15708                    for (key, mut value) in rows {
15709                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
15710                            value.templates.extend(lsp_tasks.templates);
15711                        }
15712
15713                        editor.insert_tasks(key, value);
15714                    }
15715                    for (key, value) in lsp_tasks_by_rows {
15716                        editor.insert_tasks(key, value);
15717                    }
15718                })
15719                .ok();
15720        })
15721    }
15722    fn fetch_runnable_ranges(
15723        snapshot: &DisplaySnapshot,
15724        range: Range<Anchor>,
15725    ) -> Vec<language::RunnableRange> {
15726        snapshot.buffer_snapshot().runnable_ranges(range).collect()
15727    }
15728
15729    fn runnable_rows(
15730        project: Entity<Project>,
15731        snapshot: DisplaySnapshot,
15732        prefer_lsp: bool,
15733        runnable_ranges: Vec<RunnableRange>,
15734        cx: AsyncWindowContext,
15735    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
15736        cx.spawn(async move |cx| {
15737            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
15738            for mut runnable in runnable_ranges {
15739                let Some(tasks) = cx
15740                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
15741                    .ok()
15742                else {
15743                    continue;
15744                };
15745                let mut tasks = tasks.await;
15746
15747                if prefer_lsp {
15748                    tasks.retain(|(task_kind, _)| {
15749                        !matches!(task_kind, TaskSourceKind::Language { .. })
15750                    });
15751                }
15752                if tasks.is_empty() {
15753                    continue;
15754                }
15755
15756                let point = runnable
15757                    .run_range
15758                    .start
15759                    .to_point(&snapshot.buffer_snapshot());
15760                let Some(row) = snapshot
15761                    .buffer_snapshot()
15762                    .buffer_line_for_row(MultiBufferRow(point.row))
15763                    .map(|(_, range)| range.start.row)
15764                else {
15765                    continue;
15766                };
15767
15768                let context_range =
15769                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
15770                runnable_rows.push((
15771                    (runnable.buffer_id, row),
15772                    RunnableTasks {
15773                        templates: tasks,
15774                        offset: snapshot
15775                            .buffer_snapshot()
15776                            .anchor_before(runnable.run_range.start),
15777                        context_range,
15778                        column: point.column,
15779                        extra_variables: runnable.extra_captures,
15780                    },
15781                ));
15782            }
15783            runnable_rows
15784        })
15785    }
15786
15787    fn templates_with_tags(
15788        project: &Entity<Project>,
15789        runnable: &mut Runnable,
15790        cx: &mut App,
15791    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
15792        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
15793            let (worktree_id, file) = project
15794                .buffer_for_id(runnable.buffer, cx)
15795                .and_then(|buffer| buffer.read(cx).file())
15796                .map(|file| (file.worktree_id(cx), file.clone()))
15797                .unzip();
15798
15799            (
15800                project.task_store().read(cx).task_inventory().cloned(),
15801                worktree_id,
15802                file,
15803            )
15804        });
15805
15806        let tags = mem::take(&mut runnable.tags);
15807        let language = runnable.language.clone();
15808        cx.spawn(async move |cx| {
15809            let mut templates_with_tags = Vec::new();
15810            if let Some(inventory) = inventory {
15811                for RunnableTag(tag) in tags {
15812                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
15813                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
15814                    }) else {
15815                        return templates_with_tags;
15816                    };
15817                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
15818                        move |(_, template)| {
15819                            template.tags.iter().any(|source_tag| source_tag == &tag)
15820                        },
15821                    ));
15822                }
15823            }
15824            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
15825
15826            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
15827                // Strongest source wins; if we have worktree tag binding, prefer that to
15828                // global and language bindings;
15829                // if we have a global binding, prefer that to language binding.
15830                let first_mismatch = templates_with_tags
15831                    .iter()
15832                    .position(|(tag_source, _)| tag_source != leading_tag_source);
15833                if let Some(index) = first_mismatch {
15834                    templates_with_tags.truncate(index);
15835                }
15836            }
15837
15838            templates_with_tags
15839        })
15840    }
15841
15842    pub fn move_to_enclosing_bracket(
15843        &mut self,
15844        _: &MoveToEnclosingBracket,
15845        window: &mut Window,
15846        cx: &mut Context<Self>,
15847    ) {
15848        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15849        self.change_selections(Default::default(), window, cx, |s| {
15850            s.move_offsets_with(|snapshot, selection| {
15851                let Some(enclosing_bracket_ranges) =
15852                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
15853                else {
15854                    return;
15855                };
15856
15857                let mut best_length = usize::MAX;
15858                let mut best_inside = false;
15859                let mut best_in_bracket_range = false;
15860                let mut best_destination = None;
15861                for (open, close) in enclosing_bracket_ranges {
15862                    let close = close.to_inclusive();
15863                    let length = close.end() - open.start;
15864                    let inside = selection.start >= open.end && selection.end <= *close.start();
15865                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
15866                        || close.contains(&selection.head());
15867
15868                    // If best is next to a bracket and current isn't, skip
15869                    if !in_bracket_range && best_in_bracket_range {
15870                        continue;
15871                    }
15872
15873                    // Prefer smaller lengths unless best is inside and current isn't
15874                    if length > best_length && (best_inside || !inside) {
15875                        continue;
15876                    }
15877
15878                    best_length = length;
15879                    best_inside = inside;
15880                    best_in_bracket_range = in_bracket_range;
15881                    best_destination = Some(
15882                        if close.contains(&selection.start) && close.contains(&selection.end) {
15883                            if inside { open.end } else { open.start }
15884                        } else if inside {
15885                            *close.start()
15886                        } else {
15887                            *close.end()
15888                        },
15889                    );
15890                }
15891
15892                if let Some(destination) = best_destination {
15893                    selection.collapse_to(destination, SelectionGoal::None);
15894                }
15895            })
15896        });
15897    }
15898
15899    pub fn undo_selection(
15900        &mut self,
15901        _: &UndoSelection,
15902        window: &mut Window,
15903        cx: &mut Context<Self>,
15904    ) {
15905        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15906        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
15907            self.selection_history.mode = SelectionHistoryMode::Undoing;
15908            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15909                this.end_selection(window, cx);
15910                this.change_selections(
15911                    SelectionEffects::scroll(Autoscroll::newest()),
15912                    window,
15913                    cx,
15914                    |s| s.select_anchors(entry.selections.to_vec()),
15915                );
15916            });
15917            self.selection_history.mode = SelectionHistoryMode::Normal;
15918
15919            self.select_next_state = entry.select_next_state;
15920            self.select_prev_state = entry.select_prev_state;
15921            self.add_selections_state = entry.add_selections_state;
15922        }
15923    }
15924
15925    pub fn redo_selection(
15926        &mut self,
15927        _: &RedoSelection,
15928        window: &mut Window,
15929        cx: &mut Context<Self>,
15930    ) {
15931        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15932        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
15933            self.selection_history.mode = SelectionHistoryMode::Redoing;
15934            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15935                this.end_selection(window, cx);
15936                this.change_selections(
15937                    SelectionEffects::scroll(Autoscroll::newest()),
15938                    window,
15939                    cx,
15940                    |s| s.select_anchors(entry.selections.to_vec()),
15941                );
15942            });
15943            self.selection_history.mode = SelectionHistoryMode::Normal;
15944
15945            self.select_next_state = entry.select_next_state;
15946            self.select_prev_state = entry.select_prev_state;
15947            self.add_selections_state = entry.add_selections_state;
15948        }
15949    }
15950
15951    pub fn expand_excerpts(
15952        &mut self,
15953        action: &ExpandExcerpts,
15954        _: &mut Window,
15955        cx: &mut Context<Self>,
15956    ) {
15957        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
15958    }
15959
15960    pub fn expand_excerpts_down(
15961        &mut self,
15962        action: &ExpandExcerptsDown,
15963        _: &mut Window,
15964        cx: &mut Context<Self>,
15965    ) {
15966        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
15967    }
15968
15969    pub fn expand_excerpts_up(
15970        &mut self,
15971        action: &ExpandExcerptsUp,
15972        _: &mut Window,
15973        cx: &mut Context<Self>,
15974    ) {
15975        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
15976    }
15977
15978    pub fn expand_excerpts_for_direction(
15979        &mut self,
15980        lines: u32,
15981        direction: ExpandExcerptDirection,
15982
15983        cx: &mut Context<Self>,
15984    ) {
15985        let selections = self.selections.disjoint_anchors_arc();
15986
15987        let lines = if lines == 0 {
15988            EditorSettings::get_global(cx).expand_excerpt_lines
15989        } else {
15990            lines
15991        };
15992
15993        self.buffer.update(cx, |buffer, cx| {
15994            let snapshot = buffer.snapshot(cx);
15995            let mut excerpt_ids = selections
15996                .iter()
15997                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
15998                .collect::<Vec<_>>();
15999            excerpt_ids.sort();
16000            excerpt_ids.dedup();
16001            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
16002        })
16003    }
16004
16005    pub fn expand_excerpt(
16006        &mut self,
16007        excerpt: ExcerptId,
16008        direction: ExpandExcerptDirection,
16009        window: &mut Window,
16010        cx: &mut Context<Self>,
16011    ) {
16012        let current_scroll_position = self.scroll_position(cx);
16013        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
16014        let mut scroll = None;
16015
16016        if direction == ExpandExcerptDirection::Down {
16017            let multi_buffer = self.buffer.read(cx);
16018            let snapshot = multi_buffer.snapshot(cx);
16019            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt)
16020                && let Some(buffer) = multi_buffer.buffer(buffer_id)
16021                && let Some(excerpt_range) = snapshot.context_range_for_excerpt(excerpt)
16022            {
16023                let buffer_snapshot = buffer.read(cx).snapshot();
16024                let excerpt_end_row = Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
16025                let last_row = buffer_snapshot.max_point().row;
16026                let lines_below = last_row.saturating_sub(excerpt_end_row);
16027                if lines_below >= lines_to_expand {
16028                    scroll = Some(
16029                        current_scroll_position
16030                            + gpui::Point::new(0.0, lines_to_expand as ScrollOffset),
16031                    );
16032                }
16033            }
16034        }
16035        if direction == ExpandExcerptDirection::Up
16036            && self
16037                .buffer
16038                .read(cx)
16039                .snapshot(cx)
16040                .excerpt_before(excerpt)
16041                .is_none()
16042        {
16043            scroll = Some(current_scroll_position);
16044        }
16045
16046        self.buffer.update(cx, |buffer, cx| {
16047            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
16048        });
16049
16050        if let Some(new_scroll_position) = scroll {
16051            self.set_scroll_position(new_scroll_position, window, cx);
16052        }
16053    }
16054
16055    pub fn go_to_singleton_buffer_point(
16056        &mut self,
16057        point: Point,
16058        window: &mut Window,
16059        cx: &mut Context<Self>,
16060    ) {
16061        self.go_to_singleton_buffer_range(point..point, window, cx);
16062    }
16063
16064    pub fn go_to_singleton_buffer_range(
16065        &mut self,
16066        range: Range<Point>,
16067        window: &mut Window,
16068        cx: &mut Context<Self>,
16069    ) {
16070        let multibuffer = self.buffer().read(cx);
16071        let Some(buffer) = multibuffer.as_singleton() else {
16072            return;
16073        };
16074        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
16075            return;
16076        };
16077        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
16078            return;
16079        };
16080        self.change_selections(
16081            SelectionEffects::default().nav_history(true),
16082            window,
16083            cx,
16084            |s| s.select_anchor_ranges([start..end]),
16085        );
16086    }
16087
16088    pub fn go_to_diagnostic(
16089        &mut self,
16090        action: &GoToDiagnostic,
16091        window: &mut Window,
16092        cx: &mut Context<Self>,
16093    ) {
16094        if !self.diagnostics_enabled() {
16095            return;
16096        }
16097        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16098        self.go_to_diagnostic_impl(Direction::Next, action.severity, window, cx)
16099    }
16100
16101    pub fn go_to_prev_diagnostic(
16102        &mut self,
16103        action: &GoToPreviousDiagnostic,
16104        window: &mut Window,
16105        cx: &mut Context<Self>,
16106    ) {
16107        if !self.diagnostics_enabled() {
16108            return;
16109        }
16110        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16111        self.go_to_diagnostic_impl(Direction::Prev, action.severity, window, cx)
16112    }
16113
16114    pub fn go_to_diagnostic_impl(
16115        &mut self,
16116        direction: Direction,
16117        severity: GoToDiagnosticSeverityFilter,
16118        window: &mut Window,
16119        cx: &mut Context<Self>,
16120    ) {
16121        let buffer = self.buffer.read(cx).snapshot(cx);
16122        let selection = self.selections.newest::<usize>(&self.display_snapshot(cx));
16123
16124        let mut active_group_id = None;
16125        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics
16126            && active_group.active_range.start.to_offset(&buffer) == selection.start
16127        {
16128            active_group_id = Some(active_group.group_id);
16129        }
16130
16131        fn filtered<'a>(
16132            severity: GoToDiagnosticSeverityFilter,
16133            diagnostics: impl Iterator<Item = DiagnosticEntryRef<'a, usize>>,
16134        ) -> impl Iterator<Item = DiagnosticEntryRef<'a, usize>> {
16135            diagnostics
16136                .filter(move |entry| severity.matches(entry.diagnostic.severity))
16137                .filter(|entry| entry.range.start != entry.range.end)
16138                .filter(|entry| !entry.diagnostic.is_unnecessary)
16139        }
16140
16141        let before = filtered(
16142            severity,
16143            buffer
16144                .diagnostics_in_range(0..selection.start)
16145                .filter(|entry| entry.range.start <= selection.start),
16146        );
16147        let after = filtered(
16148            severity,
16149            buffer
16150                .diagnostics_in_range(selection.start..buffer.len())
16151                .filter(|entry| entry.range.start >= selection.start),
16152        );
16153
16154        let mut found: Option<DiagnosticEntryRef<usize>> = None;
16155        if direction == Direction::Prev {
16156            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
16157            {
16158                for diagnostic in prev_diagnostics.into_iter().rev() {
16159                    if diagnostic.range.start != selection.start
16160                        || active_group_id
16161                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
16162                    {
16163                        found = Some(diagnostic);
16164                        break 'outer;
16165                    }
16166                }
16167            }
16168        } else {
16169            for diagnostic in after.chain(before) {
16170                if diagnostic.range.start != selection.start
16171                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
16172                {
16173                    found = Some(diagnostic);
16174                    break;
16175                }
16176            }
16177        }
16178        let Some(next_diagnostic) = found else {
16179            return;
16180        };
16181
16182        let next_diagnostic_start = buffer.anchor_after(next_diagnostic.range.start);
16183        let Some(buffer_id) = buffer.buffer_id_for_anchor(next_diagnostic_start) else {
16184            return;
16185        };
16186        let snapshot = self.snapshot(window, cx);
16187        if snapshot.intersects_fold(next_diagnostic.range.start) {
16188            self.unfold_ranges(
16189                std::slice::from_ref(&next_diagnostic.range),
16190                true,
16191                false,
16192                cx,
16193            );
16194        }
16195        self.change_selections(Default::default(), window, cx, |s| {
16196            s.select_ranges(vec![
16197                next_diagnostic.range.start..next_diagnostic.range.start,
16198            ])
16199        });
16200        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
16201        self.refresh_edit_prediction(false, true, window, cx);
16202    }
16203
16204    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
16205        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16206        let snapshot = self.snapshot(window, cx);
16207        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
16208        self.go_to_hunk_before_or_after_position(
16209            &snapshot,
16210            selection.head(),
16211            Direction::Next,
16212            window,
16213            cx,
16214        );
16215    }
16216
16217    pub fn go_to_hunk_before_or_after_position(
16218        &mut self,
16219        snapshot: &EditorSnapshot,
16220        position: Point,
16221        direction: Direction,
16222        window: &mut Window,
16223        cx: &mut Context<Editor>,
16224    ) {
16225        let row = if direction == Direction::Next {
16226            self.hunk_after_position(snapshot, position)
16227                .map(|hunk| hunk.row_range.start)
16228        } else {
16229            self.hunk_before_position(snapshot, position)
16230        };
16231
16232        if let Some(row) = row {
16233            let destination = Point::new(row.0, 0);
16234            let autoscroll = Autoscroll::center();
16235
16236            self.unfold_ranges(&[destination..destination], false, false, cx);
16237            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16238                s.select_ranges([destination..destination]);
16239            });
16240        }
16241    }
16242
16243    fn hunk_after_position(
16244        &mut self,
16245        snapshot: &EditorSnapshot,
16246        position: Point,
16247    ) -> Option<MultiBufferDiffHunk> {
16248        snapshot
16249            .buffer_snapshot()
16250            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
16251            .find(|hunk| hunk.row_range.start.0 > position.row)
16252            .or_else(|| {
16253                snapshot
16254                    .buffer_snapshot()
16255                    .diff_hunks_in_range(Point::zero()..position)
16256                    .find(|hunk| hunk.row_range.end.0 < position.row)
16257            })
16258    }
16259
16260    fn go_to_prev_hunk(
16261        &mut self,
16262        _: &GoToPreviousHunk,
16263        window: &mut Window,
16264        cx: &mut Context<Self>,
16265    ) {
16266        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16267        let snapshot = self.snapshot(window, cx);
16268        let selection = self.selections.newest::<Point>(&snapshot.display_snapshot);
16269        self.go_to_hunk_before_or_after_position(
16270            &snapshot,
16271            selection.head(),
16272            Direction::Prev,
16273            window,
16274            cx,
16275        );
16276    }
16277
16278    fn hunk_before_position(
16279        &mut self,
16280        snapshot: &EditorSnapshot,
16281        position: Point,
16282    ) -> Option<MultiBufferRow> {
16283        snapshot
16284            .buffer_snapshot()
16285            .diff_hunk_before(position)
16286            .or_else(|| snapshot.buffer_snapshot().diff_hunk_before(Point::MAX))
16287    }
16288
16289    fn go_to_next_change(
16290        &mut self,
16291        _: &GoToNextChange,
16292        window: &mut Window,
16293        cx: &mut Context<Self>,
16294    ) {
16295        if let Some(selections) = self
16296            .change_list
16297            .next_change(1, Direction::Next)
16298            .map(|s| s.to_vec())
16299        {
16300            self.change_selections(Default::default(), window, cx, |s| {
16301                let map = s.display_snapshot();
16302                s.select_display_ranges(selections.iter().map(|a| {
16303                    let point = a.to_display_point(&map);
16304                    point..point
16305                }))
16306            })
16307        }
16308    }
16309
16310    fn go_to_previous_change(
16311        &mut self,
16312        _: &GoToPreviousChange,
16313        window: &mut Window,
16314        cx: &mut Context<Self>,
16315    ) {
16316        if let Some(selections) = self
16317            .change_list
16318            .next_change(1, Direction::Prev)
16319            .map(|s| s.to_vec())
16320        {
16321            self.change_selections(Default::default(), window, cx, |s| {
16322                let map = s.display_snapshot();
16323                s.select_display_ranges(selections.iter().map(|a| {
16324                    let point = a.to_display_point(&map);
16325                    point..point
16326                }))
16327            })
16328        }
16329    }
16330
16331    pub fn go_to_next_document_highlight(
16332        &mut self,
16333        _: &GoToNextDocumentHighlight,
16334        window: &mut Window,
16335        cx: &mut Context<Self>,
16336    ) {
16337        self.go_to_document_highlight_before_or_after_position(Direction::Next, window, cx);
16338    }
16339
16340    pub fn go_to_prev_document_highlight(
16341        &mut self,
16342        _: &GoToPreviousDocumentHighlight,
16343        window: &mut Window,
16344        cx: &mut Context<Self>,
16345    ) {
16346        self.go_to_document_highlight_before_or_after_position(Direction::Prev, window, cx);
16347    }
16348
16349    pub fn go_to_document_highlight_before_or_after_position(
16350        &mut self,
16351        direction: Direction,
16352        window: &mut Window,
16353        cx: &mut Context<Editor>,
16354    ) {
16355        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16356        let snapshot = self.snapshot(window, cx);
16357        let buffer = &snapshot.buffer_snapshot();
16358        let position = self
16359            .selections
16360            .newest::<Point>(&snapshot.display_snapshot)
16361            .head();
16362        let anchor_position = buffer.anchor_after(position);
16363
16364        // Get all document highlights (both read and write)
16365        let mut all_highlights = Vec::new();
16366
16367        if let Some((_, read_highlights)) = self
16368            .background_highlights
16369            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
16370        {
16371            all_highlights.extend(read_highlights.iter());
16372        }
16373
16374        if let Some((_, write_highlights)) = self
16375            .background_highlights
16376            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
16377        {
16378            all_highlights.extend(write_highlights.iter());
16379        }
16380
16381        if all_highlights.is_empty() {
16382            return;
16383        }
16384
16385        // Sort highlights by position
16386        all_highlights.sort_by(|a, b| a.start.cmp(&b.start, buffer));
16387
16388        let target_highlight = match direction {
16389            Direction::Next => {
16390                // Find the first highlight after the current position
16391                all_highlights
16392                    .iter()
16393                    .find(|highlight| highlight.start.cmp(&anchor_position, buffer).is_gt())
16394            }
16395            Direction::Prev => {
16396                // Find the last highlight before the current position
16397                all_highlights
16398                    .iter()
16399                    .rev()
16400                    .find(|highlight| highlight.end.cmp(&anchor_position, buffer).is_lt())
16401            }
16402        };
16403
16404        if let Some(highlight) = target_highlight {
16405            let destination = highlight.start.to_point(buffer);
16406            let autoscroll = Autoscroll::center();
16407
16408            self.unfold_ranges(&[destination..destination], false, false, cx);
16409            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16410                s.select_ranges([destination..destination]);
16411            });
16412        }
16413    }
16414
16415    fn go_to_line<T: 'static>(
16416        &mut self,
16417        position: Anchor,
16418        highlight_color: Option<Hsla>,
16419        window: &mut Window,
16420        cx: &mut Context<Self>,
16421    ) {
16422        let snapshot = self.snapshot(window, cx).display_snapshot;
16423        let position = position.to_point(&snapshot.buffer_snapshot());
16424        let start = snapshot
16425            .buffer_snapshot()
16426            .clip_point(Point::new(position.row, 0), Bias::Left);
16427        let end = start + Point::new(1, 0);
16428        let start = snapshot.buffer_snapshot().anchor_before(start);
16429        let end = snapshot.buffer_snapshot().anchor_before(end);
16430
16431        self.highlight_rows::<T>(
16432            start..end,
16433            highlight_color
16434                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
16435            Default::default(),
16436            cx,
16437        );
16438
16439        if self.buffer.read(cx).is_singleton() {
16440            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
16441        }
16442    }
16443
16444    pub fn go_to_definition(
16445        &mut self,
16446        _: &GoToDefinition,
16447        window: &mut Window,
16448        cx: &mut Context<Self>,
16449    ) -> Task<Result<Navigated>> {
16450        let definition =
16451            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
16452        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
16453        cx.spawn_in(window, async move |editor, cx| {
16454            if definition.await? == Navigated::Yes {
16455                return Ok(Navigated::Yes);
16456            }
16457            match fallback_strategy {
16458                GoToDefinitionFallback::None => Ok(Navigated::No),
16459                GoToDefinitionFallback::FindAllReferences => {
16460                    match editor.update_in(cx, |editor, window, cx| {
16461                        editor.find_all_references(&FindAllReferences, window, cx)
16462                    })? {
16463                        Some(references) => references.await,
16464                        None => Ok(Navigated::No),
16465                    }
16466                }
16467            }
16468        })
16469    }
16470
16471    pub fn go_to_declaration(
16472        &mut self,
16473        _: &GoToDeclaration,
16474        window: &mut Window,
16475        cx: &mut Context<Self>,
16476    ) -> Task<Result<Navigated>> {
16477        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
16478    }
16479
16480    pub fn go_to_declaration_split(
16481        &mut self,
16482        _: &GoToDeclaration,
16483        window: &mut Window,
16484        cx: &mut Context<Self>,
16485    ) -> Task<Result<Navigated>> {
16486        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
16487    }
16488
16489    pub fn go_to_implementation(
16490        &mut self,
16491        _: &GoToImplementation,
16492        window: &mut Window,
16493        cx: &mut Context<Self>,
16494    ) -> Task<Result<Navigated>> {
16495        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
16496    }
16497
16498    pub fn go_to_implementation_split(
16499        &mut self,
16500        _: &GoToImplementationSplit,
16501        window: &mut Window,
16502        cx: &mut Context<Self>,
16503    ) -> Task<Result<Navigated>> {
16504        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
16505    }
16506
16507    pub fn go_to_type_definition(
16508        &mut self,
16509        _: &GoToTypeDefinition,
16510        window: &mut Window,
16511        cx: &mut Context<Self>,
16512    ) -> Task<Result<Navigated>> {
16513        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
16514    }
16515
16516    pub fn go_to_definition_split(
16517        &mut self,
16518        _: &GoToDefinitionSplit,
16519        window: &mut Window,
16520        cx: &mut Context<Self>,
16521    ) -> Task<Result<Navigated>> {
16522        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
16523    }
16524
16525    pub fn go_to_type_definition_split(
16526        &mut self,
16527        _: &GoToTypeDefinitionSplit,
16528        window: &mut Window,
16529        cx: &mut Context<Self>,
16530    ) -> Task<Result<Navigated>> {
16531        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
16532    }
16533
16534    fn go_to_definition_of_kind(
16535        &mut self,
16536        kind: GotoDefinitionKind,
16537        split: bool,
16538        window: &mut Window,
16539        cx: &mut Context<Self>,
16540    ) -> Task<Result<Navigated>> {
16541        let Some(provider) = self.semantics_provider.clone() else {
16542            return Task::ready(Ok(Navigated::No));
16543        };
16544        let head = self
16545            .selections
16546            .newest::<usize>(&self.display_snapshot(cx))
16547            .head();
16548        let buffer = self.buffer.read(cx);
16549        let Some((buffer, head)) = buffer.text_anchor_for_position(head, cx) else {
16550            return Task::ready(Ok(Navigated::No));
16551        };
16552        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
16553            return Task::ready(Ok(Navigated::No));
16554        };
16555
16556        cx.spawn_in(window, async move |editor, cx| {
16557            let Some(definitions) = definitions.await? else {
16558                return Ok(Navigated::No);
16559            };
16560            let navigated = editor
16561                .update_in(cx, |editor, window, cx| {
16562                    editor.navigate_to_hover_links(
16563                        Some(kind),
16564                        definitions
16565                            .into_iter()
16566                            .filter(|location| {
16567                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
16568                            })
16569                            .map(HoverLink::Text)
16570                            .collect::<Vec<_>>(),
16571                        split,
16572                        window,
16573                        cx,
16574                    )
16575                })?
16576                .await?;
16577            anyhow::Ok(navigated)
16578        })
16579    }
16580
16581    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
16582        let selection = self.selections.newest_anchor();
16583        let head = selection.head();
16584        let tail = selection.tail();
16585
16586        let Some((buffer, start_position)) =
16587            self.buffer.read(cx).text_anchor_for_position(head, cx)
16588        else {
16589            return;
16590        };
16591
16592        let end_position = if head != tail {
16593            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
16594                return;
16595            };
16596            Some(pos)
16597        } else {
16598            None
16599        };
16600
16601        let url_finder = cx.spawn_in(window, async move |_editor, cx| {
16602            let url = if let Some(end_pos) = end_position {
16603                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
16604            } else {
16605                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
16606            };
16607
16608            if let Some(url) = url {
16609                cx.update(|window, cx| {
16610                    if parse_zed_link(&url, cx).is_some() {
16611                        window.dispatch_action(Box::new(zed_actions::OpenZedUrl { url }), cx);
16612                    } else {
16613                        cx.open_url(&url);
16614                    }
16615                })?;
16616            }
16617
16618            anyhow::Ok(())
16619        });
16620
16621        url_finder.detach();
16622    }
16623
16624    pub fn open_selected_filename(
16625        &mut self,
16626        _: &OpenSelectedFilename,
16627        window: &mut Window,
16628        cx: &mut Context<Self>,
16629    ) {
16630        let Some(workspace) = self.workspace() else {
16631            return;
16632        };
16633
16634        let position = self.selections.newest_anchor().head();
16635
16636        let Some((buffer, buffer_position)) =
16637            self.buffer.read(cx).text_anchor_for_position(position, cx)
16638        else {
16639            return;
16640        };
16641
16642        let project = self.project.clone();
16643
16644        cx.spawn_in(window, async move |_, cx| {
16645            let result = find_file(&buffer, project, buffer_position, cx).await;
16646
16647            if let Some((_, path)) = result {
16648                workspace
16649                    .update_in(cx, |workspace, window, cx| {
16650                        workspace.open_resolved_path(path, window, cx)
16651                    })?
16652                    .await?;
16653            }
16654            anyhow::Ok(())
16655        })
16656        .detach();
16657    }
16658
16659    pub(crate) fn navigate_to_hover_links(
16660        &mut self,
16661        kind: Option<GotoDefinitionKind>,
16662        definitions: Vec<HoverLink>,
16663        split: bool,
16664        window: &mut Window,
16665        cx: &mut Context<Editor>,
16666    ) -> Task<Result<Navigated>> {
16667        // Separate out url and file links, we can only handle one of them at most or an arbitrary number of locations
16668        let mut first_url_or_file = None;
16669        let definitions: Vec<_> = definitions
16670            .into_iter()
16671            .filter_map(|def| match def {
16672                HoverLink::Text(link) => Some(Task::ready(anyhow::Ok(Some(link.target)))),
16673                HoverLink::InlayHint(lsp_location, server_id) => {
16674                    let computation =
16675                        self.compute_target_location(lsp_location, server_id, window, cx);
16676                    Some(cx.background_spawn(computation))
16677                }
16678                HoverLink::Url(url) => {
16679                    first_url_or_file = Some(Either::Left(url));
16680                    None
16681                }
16682                HoverLink::File(path) => {
16683                    first_url_or_file = Some(Either::Right(path));
16684                    None
16685                }
16686            })
16687            .collect();
16688
16689        let workspace = self.workspace();
16690
16691        cx.spawn_in(window, async move |editor, cx| {
16692            let locations: Vec<Location> = future::join_all(definitions)
16693                .await
16694                .into_iter()
16695                .filter_map(|location| location.transpose())
16696                .collect::<Result<_>>()
16697                .context("location tasks")?;
16698            let mut locations = cx.update(|_, cx| {
16699                locations
16700                    .into_iter()
16701                    .map(|location| {
16702                        let buffer = location.buffer.read(cx);
16703                        (location.buffer, location.range.to_point(buffer))
16704                    })
16705                    .into_group_map()
16706            })?;
16707            let mut num_locations = 0;
16708            for ranges in locations.values_mut() {
16709                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
16710                ranges.dedup();
16711                num_locations += ranges.len();
16712            }
16713
16714            if num_locations > 1 {
16715                let Some(workspace) = workspace else {
16716                    return Ok(Navigated::No);
16717                };
16718
16719                let tab_kind = match kind {
16720                    Some(GotoDefinitionKind::Implementation) => "Implementations",
16721                    Some(GotoDefinitionKind::Symbol) | None => "Definitions",
16722                    Some(GotoDefinitionKind::Declaration) => "Declarations",
16723                    Some(GotoDefinitionKind::Type) => "Types",
16724                };
16725                let title = editor
16726                    .update_in(cx, |_, _, cx| {
16727                        let target = locations
16728                            .iter()
16729                            .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
16730                            .map(|(buffer, location)| {
16731                                buffer
16732                                    .read(cx)
16733                                    .text_for_range(location.clone())
16734                                    .collect::<String>()
16735                            })
16736                            .filter(|text| !text.contains('\n'))
16737                            .unique()
16738                            .take(3)
16739                            .join(", ");
16740                        if target.is_empty() {
16741                            tab_kind.to_owned()
16742                        } else {
16743                            format!("{tab_kind} for {target}")
16744                        }
16745                    })
16746                    .context("buffer title")?;
16747
16748                let opened = workspace
16749                    .update_in(cx, |workspace, window, cx| {
16750                        Self::open_locations_in_multibuffer(
16751                            workspace,
16752                            locations,
16753                            title,
16754                            split,
16755                            MultibufferSelectionMode::First,
16756                            window,
16757                            cx,
16758                        )
16759                    })
16760                    .is_ok();
16761
16762                anyhow::Ok(Navigated::from_bool(opened))
16763            } else if num_locations == 0 {
16764                // If there is one url or file, open it directly
16765                match first_url_or_file {
16766                    Some(Either::Left(url)) => {
16767                        cx.update(|_, cx| cx.open_url(&url))?;
16768                        Ok(Navigated::Yes)
16769                    }
16770                    Some(Either::Right(path)) => {
16771                        let Some(workspace) = workspace else {
16772                            return Ok(Navigated::No);
16773                        };
16774
16775                        workspace
16776                            .update_in(cx, |workspace, window, cx| {
16777                                workspace.open_resolved_path(path, window, cx)
16778                            })?
16779                            .await?;
16780                        Ok(Navigated::Yes)
16781                    }
16782                    None => Ok(Navigated::No),
16783                }
16784            } else {
16785                let Some(workspace) = workspace else {
16786                    return Ok(Navigated::No);
16787                };
16788
16789                let (target_buffer, target_ranges) = locations.into_iter().next().unwrap();
16790                let target_range = target_ranges.first().unwrap().clone();
16791
16792                editor.update_in(cx, |editor, window, cx| {
16793                    let range = target_range.to_point(target_buffer.read(cx));
16794                    let range = editor.range_for_match(&range, false);
16795                    let range = collapse_multiline_range(range);
16796
16797                    if !split
16798                        && Some(&target_buffer) == editor.buffer.read(cx).as_singleton().as_ref()
16799                    {
16800                        editor.go_to_singleton_buffer_range(range, window, cx);
16801                    } else {
16802                        let pane = workspace.read(cx).active_pane().clone();
16803                        window.defer(cx, move |window, cx| {
16804                            let target_editor: Entity<Self> =
16805                                workspace.update(cx, |workspace, cx| {
16806                                    let pane = if split {
16807                                        workspace.adjacent_pane(window, cx)
16808                                    } else {
16809                                        workspace.active_pane().clone()
16810                                    };
16811
16812                                    workspace.open_project_item(
16813                                        pane,
16814                                        target_buffer.clone(),
16815                                        true,
16816                                        true,
16817                                        window,
16818                                        cx,
16819                                    )
16820                                });
16821                            target_editor.update(cx, |target_editor, cx| {
16822                                // When selecting a definition in a different buffer, disable the nav history
16823                                // to avoid creating a history entry at the previous cursor location.
16824                                pane.update(cx, |pane, _| pane.disable_history());
16825                                target_editor.go_to_singleton_buffer_range(range, window, cx);
16826                                pane.update(cx, |pane, _| pane.enable_history());
16827                            });
16828                        });
16829                    }
16830                    Navigated::Yes
16831                })
16832            }
16833        })
16834    }
16835
16836    fn compute_target_location(
16837        &self,
16838        lsp_location: lsp::Location,
16839        server_id: LanguageServerId,
16840        window: &mut Window,
16841        cx: &mut Context<Self>,
16842    ) -> Task<anyhow::Result<Option<Location>>> {
16843        let Some(project) = self.project.clone() else {
16844            return Task::ready(Ok(None));
16845        };
16846
16847        cx.spawn_in(window, async move |editor, cx| {
16848            let location_task = editor.update(cx, |_, cx| {
16849                project.update(cx, |project, cx| {
16850                    project.open_local_buffer_via_lsp(lsp_location.uri.clone(), server_id, cx)
16851                })
16852            })?;
16853            let location = Some({
16854                let target_buffer_handle = location_task.await.context("open local buffer")?;
16855                let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
16856                    let target_start = target_buffer
16857                        .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
16858                    let target_end = target_buffer
16859                        .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
16860                    target_buffer.anchor_after(target_start)
16861                        ..target_buffer.anchor_before(target_end)
16862                })?;
16863                Location {
16864                    buffer: target_buffer_handle,
16865                    range,
16866                }
16867            });
16868            Ok(location)
16869        })
16870    }
16871
16872    fn go_to_next_reference(
16873        &mut self,
16874        _: &GoToNextReference,
16875        window: &mut Window,
16876        cx: &mut Context<Self>,
16877    ) {
16878        let task = self.go_to_reference_before_or_after_position(Direction::Next, 1, window, cx);
16879        if let Some(task) = task {
16880            task.detach();
16881        };
16882    }
16883
16884    fn go_to_prev_reference(
16885        &mut self,
16886        _: &GoToPreviousReference,
16887        window: &mut Window,
16888        cx: &mut Context<Self>,
16889    ) {
16890        let task = self.go_to_reference_before_or_after_position(Direction::Prev, 1, window, cx);
16891        if let Some(task) = task {
16892            task.detach();
16893        };
16894    }
16895
16896    pub fn go_to_reference_before_or_after_position(
16897        &mut self,
16898        direction: Direction,
16899        count: usize,
16900        window: &mut Window,
16901        cx: &mut Context<Self>,
16902    ) -> Option<Task<Result<()>>> {
16903        let selection = self.selections.newest_anchor();
16904        let head = selection.head();
16905
16906        let multi_buffer = self.buffer.read(cx);
16907
16908        let (buffer, text_head) = multi_buffer.text_anchor_for_position(head, cx)?;
16909        let workspace = self.workspace()?;
16910        let project = workspace.read(cx).project().clone();
16911        let references =
16912            project.update(cx, |project, cx| project.references(&buffer, text_head, cx));
16913        Some(cx.spawn_in(window, async move |editor, cx| -> Result<()> {
16914            let Some(locations) = references.await? else {
16915                return Ok(());
16916            };
16917
16918            if locations.is_empty() {
16919                // totally normal - the cursor may be on something which is not
16920                // a symbol (e.g. a keyword)
16921                log::info!("no references found under cursor");
16922                return Ok(());
16923            }
16924
16925            let multi_buffer = editor.read_with(cx, |editor, _| editor.buffer().clone())?;
16926
16927            let multi_buffer_snapshot =
16928                multi_buffer.read_with(cx, |multi_buffer, cx| multi_buffer.snapshot(cx))?;
16929
16930            let (locations, current_location_index) =
16931                multi_buffer.update(cx, |multi_buffer, cx| {
16932                    let mut locations = locations
16933                        .into_iter()
16934                        .filter_map(|loc| {
16935                            let start = multi_buffer.buffer_anchor_to_anchor(
16936                                &loc.buffer,
16937                                loc.range.start,
16938                                cx,
16939                            )?;
16940                            let end = multi_buffer.buffer_anchor_to_anchor(
16941                                &loc.buffer,
16942                                loc.range.end,
16943                                cx,
16944                            )?;
16945                            Some(start..end)
16946                        })
16947                        .collect::<Vec<_>>();
16948
16949                    // There is an O(n) implementation, but given this list will be
16950                    // small (usually <100 items), the extra O(log(n)) factor isn't
16951                    // worth the (surprisingly large amount of) extra complexity.
16952                    locations
16953                        .sort_unstable_by(|l, r| l.start.cmp(&r.start, &multi_buffer_snapshot));
16954
16955                    let head_offset = head.to_offset(&multi_buffer_snapshot);
16956
16957                    let current_location_index = locations.iter().position(|loc| {
16958                        loc.start.to_offset(&multi_buffer_snapshot) <= head_offset
16959                            && loc.end.to_offset(&multi_buffer_snapshot) >= head_offset
16960                    });
16961
16962                    (locations, current_location_index)
16963                })?;
16964
16965            let Some(current_location_index) = current_location_index else {
16966                // This indicates something has gone wrong, because we already
16967                // handle the "no references" case above
16968                log::error!(
16969                    "failed to find current reference under cursor. Total references: {}",
16970                    locations.len()
16971                );
16972                return Ok(());
16973            };
16974
16975            let destination_location_index = match direction {
16976                Direction::Next => (current_location_index + count) % locations.len(),
16977                Direction::Prev => {
16978                    (current_location_index + locations.len() - count % locations.len())
16979                        % locations.len()
16980                }
16981            };
16982
16983            // TODO(cameron): is this needed?
16984            // the thinking is to avoid "jumping to the current location" (avoid
16985            // polluting "jumplist" in vim terms)
16986            if current_location_index == destination_location_index {
16987                return Ok(());
16988            }
16989
16990            let Range { start, end } = locations[destination_location_index];
16991
16992            editor.update_in(cx, |editor, window, cx| {
16993                let effects = SelectionEffects::default();
16994
16995                editor.unfold_ranges(&[start..end], false, false, cx);
16996                editor.change_selections(effects, window, cx, |s| {
16997                    s.select_ranges([start..start]);
16998                });
16999            })?;
17000
17001            Ok(())
17002        }))
17003    }
17004
17005    pub fn find_all_references(
17006        &mut self,
17007        _: &FindAllReferences,
17008        window: &mut Window,
17009        cx: &mut Context<Self>,
17010    ) -> Option<Task<Result<Navigated>>> {
17011        let selection = self.selections.newest::<usize>(&self.display_snapshot(cx));
17012        let multi_buffer = self.buffer.read(cx);
17013        let head = selection.head();
17014
17015        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
17016        let head_anchor = multi_buffer_snapshot.anchor_at(
17017            head,
17018            if head < selection.tail() {
17019                Bias::Right
17020            } else {
17021                Bias::Left
17022            },
17023        );
17024
17025        match self
17026            .find_all_references_task_sources
17027            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
17028        {
17029            Ok(_) => {
17030                log::info!(
17031                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
17032                );
17033                return None;
17034            }
17035            Err(i) => {
17036                self.find_all_references_task_sources.insert(i, head_anchor);
17037            }
17038        }
17039
17040        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
17041        let workspace = self.workspace()?;
17042        let project = workspace.read(cx).project().clone();
17043        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
17044        Some(cx.spawn_in(window, async move |editor, cx| {
17045            let _cleanup = cx.on_drop(&editor, move |editor, _| {
17046                if let Ok(i) = editor
17047                    .find_all_references_task_sources
17048                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
17049                {
17050                    editor.find_all_references_task_sources.remove(i);
17051                }
17052            });
17053
17054            let Some(locations) = references.await? else {
17055                return anyhow::Ok(Navigated::No);
17056            };
17057            let mut locations = cx.update(|_, cx| {
17058                locations
17059                    .into_iter()
17060                    .map(|location| {
17061                        let buffer = location.buffer.read(cx);
17062                        (location.buffer, location.range.to_point(buffer))
17063                    })
17064                    .into_group_map()
17065            })?;
17066            if locations.is_empty() {
17067                return anyhow::Ok(Navigated::No);
17068            }
17069            for ranges in locations.values_mut() {
17070                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
17071                ranges.dedup();
17072            }
17073
17074            workspace.update_in(cx, |workspace, window, cx| {
17075                let target = locations
17076                    .iter()
17077                    .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
17078                    .map(|(buffer, location)| {
17079                        buffer
17080                            .read(cx)
17081                            .text_for_range(location.clone())
17082                            .collect::<String>()
17083                    })
17084                    .filter(|text| !text.contains('\n'))
17085                    .unique()
17086                    .take(3)
17087                    .join(", ");
17088                let title = if target.is_empty() {
17089                    "References".to_owned()
17090                } else {
17091                    format!("References to {target}")
17092                };
17093                Self::open_locations_in_multibuffer(
17094                    workspace,
17095                    locations,
17096                    title,
17097                    false,
17098                    MultibufferSelectionMode::First,
17099                    window,
17100                    cx,
17101                );
17102                Navigated::Yes
17103            })
17104        }))
17105    }
17106
17107    /// Opens a multibuffer with the given project locations in it
17108    pub fn open_locations_in_multibuffer(
17109        workspace: &mut Workspace,
17110        locations: std::collections::HashMap<Entity<Buffer>, Vec<Range<Point>>>,
17111        title: String,
17112        split: bool,
17113        multibuffer_selection_mode: MultibufferSelectionMode,
17114        window: &mut Window,
17115        cx: &mut Context<Workspace>,
17116    ) {
17117        if locations.is_empty() {
17118            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
17119            return;
17120        }
17121
17122        let capability = workspace.project().read(cx).capability();
17123        let mut ranges = <Vec<Range<Anchor>>>::new();
17124
17125        // a key to find existing multibuffer editors with the same set of locations
17126        // to prevent us from opening more and more multibuffer tabs for searches and the like
17127        let mut key = (title.clone(), vec![]);
17128        let excerpt_buffer = cx.new(|cx| {
17129            let key = &mut key.1;
17130            let mut multibuffer = MultiBuffer::new(capability);
17131            for (buffer, mut ranges_for_buffer) in locations {
17132                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
17133                key.push((buffer.read(cx).remote_id(), ranges_for_buffer.clone()));
17134                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
17135                    PathKey::for_buffer(&buffer, cx),
17136                    buffer.clone(),
17137                    ranges_for_buffer,
17138                    multibuffer_context_lines(cx),
17139                    cx,
17140                );
17141                ranges.extend(new_ranges)
17142            }
17143
17144            multibuffer.with_title(title)
17145        });
17146        let existing = workspace.active_pane().update(cx, |pane, cx| {
17147            pane.items()
17148                .filter_map(|item| item.downcast::<Editor>())
17149                .find(|editor| {
17150                    editor
17151                        .read(cx)
17152                        .lookup_key
17153                        .as_ref()
17154                        .and_then(|it| {
17155                            it.downcast_ref::<(String, Vec<(BufferId, Vec<Range<Point>>)>)>()
17156                        })
17157                        .is_some_and(|it| *it == key)
17158                })
17159        });
17160        let editor = existing.unwrap_or_else(|| {
17161            cx.new(|cx| {
17162                let mut editor = Editor::for_multibuffer(
17163                    excerpt_buffer,
17164                    Some(workspace.project().clone()),
17165                    window,
17166                    cx,
17167                );
17168                editor.lookup_key = Some(Box::new(key));
17169                editor
17170            })
17171        });
17172        editor.update(cx, |editor, cx| match multibuffer_selection_mode {
17173            MultibufferSelectionMode::First => {
17174                if let Some(first_range) = ranges.first() {
17175                    editor.change_selections(
17176                        SelectionEffects::no_scroll(),
17177                        window,
17178                        cx,
17179                        |selections| {
17180                            selections.clear_disjoint();
17181                            selections.select_anchor_ranges(std::iter::once(first_range.clone()));
17182                        },
17183                    );
17184                }
17185                editor.highlight_background::<Self>(
17186                    &ranges,
17187                    |theme| theme.colors().editor_highlighted_line_background,
17188                    cx,
17189                );
17190            }
17191            MultibufferSelectionMode::All => {
17192                editor.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
17193                    selections.clear_disjoint();
17194                    selections.select_anchor_ranges(ranges);
17195                });
17196            }
17197        });
17198
17199        let item = Box::new(editor);
17200        let item_id = item.item_id();
17201
17202        if split {
17203            let pane = workspace.adjacent_pane(window, cx);
17204            workspace.add_item(pane, item, None, true, true, window, cx);
17205        } else if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
17206            let (preview_item_id, preview_item_idx) =
17207                workspace.active_pane().read_with(cx, |pane, _| {
17208                    (pane.preview_item_id(), pane.preview_item_idx())
17209                });
17210
17211            workspace.add_item_to_active_pane(item, preview_item_idx, true, window, cx);
17212
17213            if let Some(preview_item_id) = preview_item_id {
17214                workspace.active_pane().update(cx, |pane, cx| {
17215                    pane.remove_item(preview_item_id, false, false, window, cx);
17216                });
17217            }
17218        } else {
17219            workspace.add_item_to_active_pane(item, None, true, window, cx);
17220        }
17221        workspace.active_pane().update(cx, |pane, cx| {
17222            pane.set_preview_item_id(Some(item_id), cx);
17223        });
17224    }
17225
17226    pub fn rename(
17227        &mut self,
17228        _: &Rename,
17229        window: &mut Window,
17230        cx: &mut Context<Self>,
17231    ) -> Option<Task<Result<()>>> {
17232        use language::ToOffset as _;
17233
17234        let provider = self.semantics_provider.clone()?;
17235        let selection = self.selections.newest_anchor().clone();
17236        let (cursor_buffer, cursor_buffer_position) = self
17237            .buffer
17238            .read(cx)
17239            .text_anchor_for_position(selection.head(), cx)?;
17240        let (tail_buffer, cursor_buffer_position_end) = self
17241            .buffer
17242            .read(cx)
17243            .text_anchor_for_position(selection.tail(), cx)?;
17244        if tail_buffer != cursor_buffer {
17245            return None;
17246        }
17247
17248        let snapshot = cursor_buffer.read(cx).snapshot();
17249        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
17250        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
17251        let prepare_rename = provider
17252            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
17253            .unwrap_or_else(|| Task::ready(Ok(None)));
17254        drop(snapshot);
17255
17256        Some(cx.spawn_in(window, async move |this, cx| {
17257            let rename_range = if let Some(range) = prepare_rename.await? {
17258                Some(range)
17259            } else {
17260                this.update(cx, |this, cx| {
17261                    let buffer = this.buffer.read(cx).snapshot(cx);
17262                    let mut buffer_highlights = this
17263                        .document_highlights_for_position(selection.head(), &buffer)
17264                        .filter(|highlight| {
17265                            highlight.start.excerpt_id == selection.head().excerpt_id
17266                                && highlight.end.excerpt_id == selection.head().excerpt_id
17267                        });
17268                    buffer_highlights
17269                        .next()
17270                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
17271                })?
17272            };
17273            if let Some(rename_range) = rename_range {
17274                this.update_in(cx, |this, window, cx| {
17275                    let snapshot = cursor_buffer.read(cx).snapshot();
17276                    let rename_buffer_range = rename_range.to_offset(&snapshot);
17277                    let cursor_offset_in_rename_range =
17278                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
17279                    let cursor_offset_in_rename_range_end =
17280                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
17281
17282                    this.take_rename(false, window, cx);
17283                    let buffer = this.buffer.read(cx).read(cx);
17284                    let cursor_offset = selection.head().to_offset(&buffer);
17285                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
17286                    let rename_end = rename_start + rename_buffer_range.len();
17287                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
17288                    let mut old_highlight_id = None;
17289                    let old_name: Arc<str> = buffer
17290                        .chunks(rename_start..rename_end, true)
17291                        .map(|chunk| {
17292                            if old_highlight_id.is_none() {
17293                                old_highlight_id = chunk.syntax_highlight_id;
17294                            }
17295                            chunk.text
17296                        })
17297                        .collect::<String>()
17298                        .into();
17299
17300                    drop(buffer);
17301
17302                    // Position the selection in the rename editor so that it matches the current selection.
17303                    this.show_local_selections = false;
17304                    let rename_editor = cx.new(|cx| {
17305                        let mut editor = Editor::single_line(window, cx);
17306                        editor.buffer.update(cx, |buffer, cx| {
17307                            buffer.edit([(0..0, old_name.clone())], None, cx)
17308                        });
17309                        let rename_selection_range = match cursor_offset_in_rename_range
17310                            .cmp(&cursor_offset_in_rename_range_end)
17311                        {
17312                            Ordering::Equal => {
17313                                editor.select_all(&SelectAll, window, cx);
17314                                return editor;
17315                            }
17316                            Ordering::Less => {
17317                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
17318                            }
17319                            Ordering::Greater => {
17320                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
17321                            }
17322                        };
17323                        if rename_selection_range.end > old_name.len() {
17324                            editor.select_all(&SelectAll, window, cx);
17325                        } else {
17326                            editor.change_selections(Default::default(), window, cx, |s| {
17327                                s.select_ranges([rename_selection_range]);
17328                            });
17329                        }
17330                        editor
17331                    });
17332                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
17333                        if e == &EditorEvent::Focused {
17334                            cx.emit(EditorEvent::FocusedIn)
17335                        }
17336                    })
17337                    .detach();
17338
17339                    let write_highlights =
17340                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
17341                    let read_highlights =
17342                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
17343                    let ranges = write_highlights
17344                        .iter()
17345                        .flat_map(|(_, ranges)| ranges.iter())
17346                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
17347                        .cloned()
17348                        .collect();
17349
17350                    this.highlight_text::<Rename>(
17351                        ranges,
17352                        HighlightStyle {
17353                            fade_out: Some(0.6),
17354                            ..Default::default()
17355                        },
17356                        cx,
17357                    );
17358                    let rename_focus_handle = rename_editor.focus_handle(cx);
17359                    window.focus(&rename_focus_handle);
17360                    let block_id = this.insert_blocks(
17361                        [BlockProperties {
17362                            style: BlockStyle::Flex,
17363                            placement: BlockPlacement::Below(range.start),
17364                            height: Some(1),
17365                            render: Arc::new({
17366                                let rename_editor = rename_editor.clone();
17367                                move |cx: &mut BlockContext| {
17368                                    let mut text_style = cx.editor_style.text.clone();
17369                                    if let Some(highlight_style) = old_highlight_id
17370                                        .and_then(|h| h.style(&cx.editor_style.syntax))
17371                                    {
17372                                        text_style = text_style.highlight(highlight_style);
17373                                    }
17374                                    div()
17375                                        .block_mouse_except_scroll()
17376                                        .pl(cx.anchor_x)
17377                                        .child(EditorElement::new(
17378                                            &rename_editor,
17379                                            EditorStyle {
17380                                                background: cx.theme().system().transparent,
17381                                                local_player: cx.editor_style.local_player,
17382                                                text: text_style,
17383                                                scrollbar_width: cx.editor_style.scrollbar_width,
17384                                                syntax: cx.editor_style.syntax.clone(),
17385                                                status: cx.editor_style.status.clone(),
17386                                                inlay_hints_style: HighlightStyle {
17387                                                    font_weight: Some(FontWeight::BOLD),
17388                                                    ..make_inlay_hints_style(cx.app)
17389                                                },
17390                                                edit_prediction_styles: make_suggestion_styles(
17391                                                    cx.app,
17392                                                ),
17393                                                ..EditorStyle::default()
17394                                            },
17395                                        ))
17396                                        .into_any_element()
17397                                }
17398                            }),
17399                            priority: 0,
17400                        }],
17401                        Some(Autoscroll::fit()),
17402                        cx,
17403                    )[0];
17404                    this.pending_rename = Some(RenameState {
17405                        range,
17406                        old_name,
17407                        editor: rename_editor,
17408                        block_id,
17409                    });
17410                })?;
17411            }
17412
17413            Ok(())
17414        }))
17415    }
17416
17417    pub fn confirm_rename(
17418        &mut self,
17419        _: &ConfirmRename,
17420        window: &mut Window,
17421        cx: &mut Context<Self>,
17422    ) -> Option<Task<Result<()>>> {
17423        let rename = self.take_rename(false, window, cx)?;
17424        let workspace = self.workspace()?.downgrade();
17425        let (buffer, start) = self
17426            .buffer
17427            .read(cx)
17428            .text_anchor_for_position(rename.range.start, cx)?;
17429        let (end_buffer, _) = self
17430            .buffer
17431            .read(cx)
17432            .text_anchor_for_position(rename.range.end, cx)?;
17433        if buffer != end_buffer {
17434            return None;
17435        }
17436
17437        let old_name = rename.old_name;
17438        let new_name = rename.editor.read(cx).text(cx);
17439
17440        let rename = self.semantics_provider.as_ref()?.perform_rename(
17441            &buffer,
17442            start,
17443            new_name.clone(),
17444            cx,
17445        )?;
17446
17447        Some(cx.spawn_in(window, async move |editor, cx| {
17448            let project_transaction = rename.await?;
17449            Self::open_project_transaction(
17450                &editor,
17451                workspace,
17452                project_transaction,
17453                format!("Rename: {}{}", old_name, new_name),
17454                cx,
17455            )
17456            .await?;
17457
17458            editor.update(cx, |editor, cx| {
17459                editor.refresh_document_highlights(cx);
17460            })?;
17461            Ok(())
17462        }))
17463    }
17464
17465    fn take_rename(
17466        &mut self,
17467        moving_cursor: bool,
17468        window: &mut Window,
17469        cx: &mut Context<Self>,
17470    ) -> Option<RenameState> {
17471        let rename = self.pending_rename.take()?;
17472        if rename.editor.focus_handle(cx).is_focused(window) {
17473            window.focus(&self.focus_handle);
17474        }
17475
17476        self.remove_blocks(
17477            [rename.block_id].into_iter().collect(),
17478            Some(Autoscroll::fit()),
17479            cx,
17480        );
17481        self.clear_highlights::<Rename>(cx);
17482        self.show_local_selections = true;
17483
17484        if moving_cursor {
17485            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
17486                editor
17487                    .selections
17488                    .newest::<usize>(&editor.display_snapshot(cx))
17489                    .head()
17490            });
17491
17492            // Update the selection to match the position of the selection inside
17493            // the rename editor.
17494            let snapshot = self.buffer.read(cx).read(cx);
17495            let rename_range = rename.range.to_offset(&snapshot);
17496            let cursor_in_editor = snapshot
17497                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
17498                .min(rename_range.end);
17499            drop(snapshot);
17500
17501            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17502                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
17503            });
17504        } else {
17505            self.refresh_document_highlights(cx);
17506        }
17507
17508        Some(rename)
17509    }
17510
17511    pub fn pending_rename(&self) -> Option<&RenameState> {
17512        self.pending_rename.as_ref()
17513    }
17514
17515    fn format(
17516        &mut self,
17517        _: &Format,
17518        window: &mut Window,
17519        cx: &mut Context<Self>,
17520    ) -> Option<Task<Result<()>>> {
17521        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17522
17523        let project = match &self.project {
17524            Some(project) => project.clone(),
17525            None => return None,
17526        };
17527
17528        Some(self.perform_format(
17529            project,
17530            FormatTrigger::Manual,
17531            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
17532            window,
17533            cx,
17534        ))
17535    }
17536
17537    fn format_selections(
17538        &mut self,
17539        _: &FormatSelections,
17540        window: &mut Window,
17541        cx: &mut Context<Self>,
17542    ) -> Option<Task<Result<()>>> {
17543        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17544
17545        let project = match &self.project {
17546            Some(project) => project.clone(),
17547            None => return None,
17548        };
17549
17550        let ranges = self
17551            .selections
17552            .all_adjusted(&self.display_snapshot(cx))
17553            .into_iter()
17554            .map(|selection| selection.range())
17555            .collect_vec();
17556
17557        Some(self.perform_format(
17558            project,
17559            FormatTrigger::Manual,
17560            FormatTarget::Ranges(ranges),
17561            window,
17562            cx,
17563        ))
17564    }
17565
17566    fn perform_format(
17567        &mut self,
17568        project: Entity<Project>,
17569        trigger: FormatTrigger,
17570        target: FormatTarget,
17571        window: &mut Window,
17572        cx: &mut Context<Self>,
17573    ) -> Task<Result<()>> {
17574        let buffer = self.buffer.clone();
17575        let (buffers, target) = match target {
17576            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
17577            FormatTarget::Ranges(selection_ranges) => {
17578                let multi_buffer = buffer.read(cx);
17579                let snapshot = multi_buffer.read(cx);
17580                let mut buffers = HashSet::default();
17581                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
17582                    BTreeMap::new();
17583                for selection_range in selection_ranges {
17584                    for (buffer, buffer_range, _) in
17585                        snapshot.range_to_buffer_ranges(selection_range)
17586                    {
17587                        let buffer_id = buffer.remote_id();
17588                        let start = buffer.anchor_before(buffer_range.start);
17589                        let end = buffer.anchor_after(buffer_range.end);
17590                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
17591                        buffer_id_to_ranges
17592                            .entry(buffer_id)
17593                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
17594                            .or_insert_with(|| vec![start..end]);
17595                    }
17596                }
17597                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
17598            }
17599        };
17600
17601        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
17602        let selections_prev = transaction_id_prev
17603            .and_then(|transaction_id_prev| {
17604                // default to selections as they were after the last edit, if we have them,
17605                // instead of how they are now.
17606                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
17607                // will take you back to where you made the last edit, instead of staying where you scrolled
17608                self.selection_history
17609                    .transaction(transaction_id_prev)
17610                    .map(|t| t.0.clone())
17611            })
17612            .unwrap_or_else(|| self.selections.disjoint_anchors_arc());
17613
17614        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
17615        let format = project.update(cx, |project, cx| {
17616            project.format(buffers, target, true, trigger, cx)
17617        });
17618
17619        cx.spawn_in(window, async move |editor, cx| {
17620            let transaction = futures::select_biased! {
17621                transaction = format.log_err().fuse() => transaction,
17622                () = timeout => {
17623                    log::warn!("timed out waiting for formatting");
17624                    None
17625                }
17626            };
17627
17628            buffer
17629                .update(cx, |buffer, cx| {
17630                    if let Some(transaction) = transaction
17631                        && !buffer.is_singleton()
17632                    {
17633                        buffer.push_transaction(&transaction.0, cx);
17634                    }
17635                    cx.notify();
17636                })
17637                .ok();
17638
17639            if let Some(transaction_id_now) =
17640                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
17641            {
17642                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
17643                if has_new_transaction {
17644                    _ = editor.update(cx, |editor, _| {
17645                        editor
17646                            .selection_history
17647                            .insert_transaction(transaction_id_now, selections_prev);
17648                    });
17649                }
17650            }
17651
17652            Ok(())
17653        })
17654    }
17655
17656    fn organize_imports(
17657        &mut self,
17658        _: &OrganizeImports,
17659        window: &mut Window,
17660        cx: &mut Context<Self>,
17661    ) -> Option<Task<Result<()>>> {
17662        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17663        let project = match &self.project {
17664            Some(project) => project.clone(),
17665            None => return None,
17666        };
17667        Some(self.perform_code_action_kind(
17668            project,
17669            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
17670            window,
17671            cx,
17672        ))
17673    }
17674
17675    fn perform_code_action_kind(
17676        &mut self,
17677        project: Entity<Project>,
17678        kind: CodeActionKind,
17679        window: &mut Window,
17680        cx: &mut Context<Self>,
17681    ) -> Task<Result<()>> {
17682        let buffer = self.buffer.clone();
17683        let buffers = buffer.read(cx).all_buffers();
17684        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
17685        let apply_action = project.update(cx, |project, cx| {
17686            project.apply_code_action_kind(buffers, kind, true, cx)
17687        });
17688        cx.spawn_in(window, async move |_, cx| {
17689            let transaction = futures::select_biased! {
17690                () = timeout => {
17691                    log::warn!("timed out waiting for executing code action");
17692                    None
17693                }
17694                transaction = apply_action.log_err().fuse() => transaction,
17695            };
17696            buffer
17697                .update(cx, |buffer, cx| {
17698                    // check if we need this
17699                    if let Some(transaction) = transaction
17700                        && !buffer.is_singleton()
17701                    {
17702                        buffer.push_transaction(&transaction.0, cx);
17703                    }
17704                    cx.notify();
17705                })
17706                .ok();
17707            Ok(())
17708        })
17709    }
17710
17711    pub fn restart_language_server(
17712        &mut self,
17713        _: &RestartLanguageServer,
17714        _: &mut Window,
17715        cx: &mut Context<Self>,
17716    ) {
17717        if let Some(project) = self.project.clone() {
17718            self.buffer.update(cx, |multi_buffer, cx| {
17719                project.update(cx, |project, cx| {
17720                    project.restart_language_servers_for_buffers(
17721                        multi_buffer.all_buffers().into_iter().collect(),
17722                        HashSet::default(),
17723                        cx,
17724                    );
17725                });
17726            })
17727        }
17728    }
17729
17730    pub fn stop_language_server(
17731        &mut self,
17732        _: &StopLanguageServer,
17733        _: &mut Window,
17734        cx: &mut Context<Self>,
17735    ) {
17736        if let Some(project) = self.project.clone() {
17737            self.buffer.update(cx, |multi_buffer, cx| {
17738                project.update(cx, |project, cx| {
17739                    project.stop_language_servers_for_buffers(
17740                        multi_buffer.all_buffers().into_iter().collect(),
17741                        HashSet::default(),
17742                        cx,
17743                    );
17744                });
17745            });
17746            self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
17747        }
17748    }
17749
17750    fn cancel_language_server_work(
17751        workspace: &mut Workspace,
17752        _: &actions::CancelLanguageServerWork,
17753        _: &mut Window,
17754        cx: &mut Context<Workspace>,
17755    ) {
17756        let project = workspace.project();
17757        let buffers = workspace
17758            .active_item(cx)
17759            .and_then(|item| item.act_as::<Editor>(cx))
17760            .map_or(HashSet::default(), |editor| {
17761                editor.read(cx).buffer.read(cx).all_buffers()
17762            });
17763        project.update(cx, |project, cx| {
17764            project.cancel_language_server_work_for_buffers(buffers, cx);
17765        });
17766    }
17767
17768    fn show_character_palette(
17769        &mut self,
17770        _: &ShowCharacterPalette,
17771        window: &mut Window,
17772        _: &mut Context<Self>,
17773    ) {
17774        window.show_character_palette();
17775    }
17776
17777    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
17778        if !self.diagnostics_enabled() {
17779            return;
17780        }
17781
17782        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
17783            let buffer = self.buffer.read(cx).snapshot(cx);
17784            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
17785            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
17786            let is_valid = buffer
17787                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
17788                .any(|entry| {
17789                    entry.diagnostic.is_primary
17790                        && !entry.range.is_empty()
17791                        && entry.range.start == primary_range_start
17792                        && entry.diagnostic.message == active_diagnostics.active_message
17793                });
17794
17795            if !is_valid {
17796                self.dismiss_diagnostics(cx);
17797            }
17798        }
17799    }
17800
17801    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
17802        match &self.active_diagnostics {
17803            ActiveDiagnostic::Group(group) => Some(group),
17804            _ => None,
17805        }
17806    }
17807
17808    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
17809        if !self.diagnostics_enabled() {
17810            return;
17811        }
17812        self.dismiss_diagnostics(cx);
17813        self.active_diagnostics = ActiveDiagnostic::All;
17814    }
17815
17816    fn activate_diagnostics(
17817        &mut self,
17818        buffer_id: BufferId,
17819        diagnostic: DiagnosticEntryRef<'_, usize>,
17820        window: &mut Window,
17821        cx: &mut Context<Self>,
17822    ) {
17823        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
17824            return;
17825        }
17826        self.dismiss_diagnostics(cx);
17827        let snapshot = self.snapshot(window, cx);
17828        let buffer = self.buffer.read(cx).snapshot(cx);
17829        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
17830            return;
17831        };
17832
17833        let diagnostic_group = buffer
17834            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
17835            .collect::<Vec<_>>();
17836
17837        let blocks =
17838            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
17839
17840        let blocks = self.display_map.update(cx, |display_map, cx| {
17841            display_map.insert_blocks(blocks, cx).into_iter().collect()
17842        });
17843        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
17844            active_range: buffer.anchor_before(diagnostic.range.start)
17845                ..buffer.anchor_after(diagnostic.range.end),
17846            active_message: diagnostic.diagnostic.message.clone(),
17847            group_id: diagnostic.diagnostic.group_id,
17848            blocks,
17849        });
17850        cx.notify();
17851    }
17852
17853    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
17854        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
17855            return;
17856        };
17857
17858        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
17859        if let ActiveDiagnostic::Group(group) = prev {
17860            self.display_map.update(cx, |display_map, cx| {
17861                display_map.remove_blocks(group.blocks, cx);
17862            });
17863            cx.notify();
17864        }
17865    }
17866
17867    /// Disable inline diagnostics rendering for this editor.
17868    pub fn disable_inline_diagnostics(&mut self) {
17869        self.inline_diagnostics_enabled = false;
17870        self.inline_diagnostics_update = Task::ready(());
17871        self.inline_diagnostics.clear();
17872    }
17873
17874    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
17875        self.diagnostics_enabled = false;
17876        self.dismiss_diagnostics(cx);
17877        self.inline_diagnostics_update = Task::ready(());
17878        self.inline_diagnostics.clear();
17879    }
17880
17881    pub fn disable_word_completions(&mut self) {
17882        self.word_completions_enabled = false;
17883    }
17884
17885    pub fn diagnostics_enabled(&self) -> bool {
17886        self.diagnostics_enabled && self.mode.is_full()
17887    }
17888
17889    pub fn inline_diagnostics_enabled(&self) -> bool {
17890        self.inline_diagnostics_enabled && self.diagnostics_enabled()
17891    }
17892
17893    pub fn show_inline_diagnostics(&self) -> bool {
17894        self.show_inline_diagnostics
17895    }
17896
17897    pub fn toggle_inline_diagnostics(
17898        &mut self,
17899        _: &ToggleInlineDiagnostics,
17900        window: &mut Window,
17901        cx: &mut Context<Editor>,
17902    ) {
17903        self.show_inline_diagnostics = !self.show_inline_diagnostics;
17904        self.refresh_inline_diagnostics(false, window, cx);
17905    }
17906
17907    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
17908        self.diagnostics_max_severity = severity;
17909        self.display_map.update(cx, |display_map, _| {
17910            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
17911        });
17912    }
17913
17914    pub fn toggle_diagnostics(
17915        &mut self,
17916        _: &ToggleDiagnostics,
17917        window: &mut Window,
17918        cx: &mut Context<Editor>,
17919    ) {
17920        if !self.diagnostics_enabled() {
17921            return;
17922        }
17923
17924        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
17925            EditorSettings::get_global(cx)
17926                .diagnostics_max_severity
17927                .filter(|severity| severity != &DiagnosticSeverity::Off)
17928                .unwrap_or(DiagnosticSeverity::Hint)
17929        } else {
17930            DiagnosticSeverity::Off
17931        };
17932        self.set_max_diagnostics_severity(new_severity, cx);
17933        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
17934            self.active_diagnostics = ActiveDiagnostic::None;
17935            self.inline_diagnostics_update = Task::ready(());
17936            self.inline_diagnostics.clear();
17937        } else {
17938            self.refresh_inline_diagnostics(false, window, cx);
17939        }
17940
17941        cx.notify();
17942    }
17943
17944    pub fn toggle_minimap(
17945        &mut self,
17946        _: &ToggleMinimap,
17947        window: &mut Window,
17948        cx: &mut Context<Editor>,
17949    ) {
17950        if self.supports_minimap(cx) {
17951            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
17952        }
17953    }
17954
17955    fn refresh_inline_diagnostics(
17956        &mut self,
17957        debounce: bool,
17958        window: &mut Window,
17959        cx: &mut Context<Self>,
17960    ) {
17961        let max_severity = ProjectSettings::get_global(cx)
17962            .diagnostics
17963            .inline
17964            .max_severity
17965            .unwrap_or(self.diagnostics_max_severity);
17966
17967        if !self.inline_diagnostics_enabled()
17968            || !self.diagnostics_enabled()
17969            || !self.show_inline_diagnostics
17970            || max_severity == DiagnosticSeverity::Off
17971        {
17972            self.inline_diagnostics_update = Task::ready(());
17973            self.inline_diagnostics.clear();
17974            return;
17975        }
17976
17977        let debounce_ms = ProjectSettings::get_global(cx)
17978            .diagnostics
17979            .inline
17980            .update_debounce_ms;
17981        let debounce = if debounce && debounce_ms > 0 {
17982            Some(Duration::from_millis(debounce_ms))
17983        } else {
17984            None
17985        };
17986        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
17987            if let Some(debounce) = debounce {
17988                cx.background_executor().timer(debounce).await;
17989            }
17990            let Some(snapshot) = editor.upgrade().and_then(|editor| {
17991                editor
17992                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
17993                    .ok()
17994            }) else {
17995                return;
17996            };
17997
17998            let new_inline_diagnostics = cx
17999                .background_spawn(async move {
18000                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
18001                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
18002                        let message = diagnostic_entry
18003                            .diagnostic
18004                            .message
18005                            .split_once('\n')
18006                            .map(|(line, _)| line)
18007                            .map(SharedString::new)
18008                            .unwrap_or_else(|| {
18009                                SharedString::new(&*diagnostic_entry.diagnostic.message)
18010                            });
18011                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
18012                        let (Ok(i) | Err(i)) = inline_diagnostics
18013                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
18014                        inline_diagnostics.insert(
18015                            i,
18016                            (
18017                                start_anchor,
18018                                InlineDiagnostic {
18019                                    message,
18020                                    group_id: diagnostic_entry.diagnostic.group_id,
18021                                    start: diagnostic_entry.range.start.to_point(&snapshot),
18022                                    is_primary: diagnostic_entry.diagnostic.is_primary,
18023                                    severity: diagnostic_entry.diagnostic.severity,
18024                                },
18025                            ),
18026                        );
18027                    }
18028                    inline_diagnostics
18029                })
18030                .await;
18031
18032            editor
18033                .update(cx, |editor, cx| {
18034                    editor.inline_diagnostics = new_inline_diagnostics;
18035                    cx.notify();
18036                })
18037                .ok();
18038        });
18039    }
18040
18041    fn pull_diagnostics(
18042        &mut self,
18043        buffer_id: Option<BufferId>,
18044        window: &Window,
18045        cx: &mut Context<Self>,
18046    ) -> Option<()> {
18047        if self.ignore_lsp_data() || !self.diagnostics_enabled() {
18048            return None;
18049        }
18050        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
18051            .diagnostics
18052            .lsp_pull_diagnostics;
18053        if !pull_diagnostics_settings.enabled {
18054            return None;
18055        }
18056        let project = self.project()?.downgrade();
18057        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
18058        let mut buffers = self.buffer.read(cx).all_buffers();
18059        buffers.retain(|buffer| {
18060            let buffer_id_to_retain = buffer.read(cx).remote_id();
18061            buffer_id.is_none_or(|buffer_id| buffer_id == buffer_id_to_retain)
18062                && self.registered_buffers.contains_key(&buffer_id_to_retain)
18063        });
18064        if buffers.is_empty() {
18065            self.pull_diagnostics_task = Task::ready(());
18066            return None;
18067        }
18068
18069        self.pull_diagnostics_task = cx.spawn_in(window, async move |editor, cx| {
18070            cx.background_executor().timer(debounce).await;
18071
18072            let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
18073                buffers
18074                    .into_iter()
18075                    .filter_map(|buffer| {
18076                        project
18077                            .update(cx, |project, cx| {
18078                                project.lsp_store().update(cx, |lsp_store, cx| {
18079                                    lsp_store.pull_diagnostics_for_buffer(buffer, cx)
18080                                })
18081                            })
18082                            .ok()
18083                    })
18084                    .collect::<FuturesUnordered<_>>()
18085            }) else {
18086                return;
18087            };
18088
18089            while let Some(pull_task) = pull_diagnostics_tasks.next().await {
18090                match pull_task {
18091                    Ok(()) => {
18092                        if editor
18093                            .update_in(cx, |editor, window, cx| {
18094                                editor.update_diagnostics_state(window, cx);
18095                            })
18096                            .is_err()
18097                        {
18098                            return;
18099                        }
18100                    }
18101                    Err(e) => log::error!("Failed to update project diagnostics: {e:#}"),
18102                }
18103            }
18104        });
18105
18106        Some(())
18107    }
18108
18109    pub fn set_selections_from_remote(
18110        &mut self,
18111        selections: Vec<Selection<Anchor>>,
18112        pending_selection: Option<Selection<Anchor>>,
18113        window: &mut Window,
18114        cx: &mut Context<Self>,
18115    ) {
18116        let old_cursor_position = self.selections.newest_anchor().head();
18117        self.selections
18118            .change_with(&self.display_snapshot(cx), |s| {
18119                s.select_anchors(selections);
18120                if let Some(pending_selection) = pending_selection {
18121                    s.set_pending(pending_selection, SelectMode::Character);
18122                } else {
18123                    s.clear_pending();
18124                }
18125            });
18126        self.selections_did_change(
18127            false,
18128            &old_cursor_position,
18129            SelectionEffects::default(),
18130            window,
18131            cx,
18132        );
18133    }
18134
18135    pub fn transact(
18136        &mut self,
18137        window: &mut Window,
18138        cx: &mut Context<Self>,
18139        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
18140    ) -> Option<TransactionId> {
18141        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
18142            this.start_transaction_at(Instant::now(), window, cx);
18143            update(this, window, cx);
18144            this.end_transaction_at(Instant::now(), cx)
18145        })
18146    }
18147
18148    pub fn start_transaction_at(
18149        &mut self,
18150        now: Instant,
18151        window: &mut Window,
18152        cx: &mut Context<Self>,
18153    ) -> Option<TransactionId> {
18154        self.end_selection(window, cx);
18155        if let Some(tx_id) = self
18156            .buffer
18157            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
18158        {
18159            self.selection_history
18160                .insert_transaction(tx_id, self.selections.disjoint_anchors_arc());
18161            cx.emit(EditorEvent::TransactionBegun {
18162                transaction_id: tx_id,
18163            });
18164            Some(tx_id)
18165        } else {
18166            None
18167        }
18168    }
18169
18170    pub fn end_transaction_at(
18171        &mut self,
18172        now: Instant,
18173        cx: &mut Context<Self>,
18174    ) -> Option<TransactionId> {
18175        if let Some(transaction_id) = self
18176            .buffer
18177            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
18178        {
18179            if let Some((_, end_selections)) =
18180                self.selection_history.transaction_mut(transaction_id)
18181            {
18182                *end_selections = Some(self.selections.disjoint_anchors_arc());
18183            } else {
18184                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
18185            }
18186
18187            cx.emit(EditorEvent::Edited { transaction_id });
18188            Some(transaction_id)
18189        } else {
18190            None
18191        }
18192    }
18193
18194    pub fn modify_transaction_selection_history(
18195        &mut self,
18196        transaction_id: TransactionId,
18197        modify: impl FnOnce(&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)),
18198    ) -> bool {
18199        self.selection_history
18200            .transaction_mut(transaction_id)
18201            .map(modify)
18202            .is_some()
18203    }
18204
18205    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
18206        if self.selection_mark_mode {
18207            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
18208                s.move_with(|_, sel| {
18209                    sel.collapse_to(sel.head(), SelectionGoal::None);
18210                });
18211            })
18212        }
18213        self.selection_mark_mode = true;
18214        cx.notify();
18215    }
18216
18217    pub fn swap_selection_ends(
18218        &mut self,
18219        _: &actions::SwapSelectionEnds,
18220        window: &mut Window,
18221        cx: &mut Context<Self>,
18222    ) {
18223        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
18224            s.move_with(|_, sel| {
18225                if sel.start != sel.end {
18226                    sel.reversed = !sel.reversed
18227                }
18228            });
18229        });
18230        self.request_autoscroll(Autoscroll::newest(), cx);
18231        cx.notify();
18232    }
18233
18234    pub fn toggle_focus(
18235        workspace: &mut Workspace,
18236        _: &actions::ToggleFocus,
18237        window: &mut Window,
18238        cx: &mut Context<Workspace>,
18239    ) {
18240        let Some(item) = workspace.recent_active_item_by_type::<Self>(cx) else {
18241            return;
18242        };
18243        workspace.activate_item(&item, true, true, window, cx);
18244    }
18245
18246    pub fn toggle_fold(
18247        &mut self,
18248        _: &actions::ToggleFold,
18249        window: &mut Window,
18250        cx: &mut Context<Self>,
18251    ) {
18252        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18253            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18254            let selection = self.selections.newest::<Point>(&display_map);
18255
18256            let range = if selection.is_empty() {
18257                let point = selection.head().to_display_point(&display_map);
18258                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
18259                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
18260                    .to_point(&display_map);
18261                start..end
18262            } else {
18263                selection.range()
18264            };
18265            if display_map.folds_in_range(range).next().is_some() {
18266                self.unfold_lines(&Default::default(), window, cx)
18267            } else {
18268                self.fold(&Default::default(), window, cx)
18269            }
18270        } else {
18271            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18272            let buffer_ids: HashSet<_> = self
18273                .selections
18274                .disjoint_anchor_ranges()
18275                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18276                .collect();
18277
18278            let should_unfold = buffer_ids
18279                .iter()
18280                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
18281
18282            for buffer_id in buffer_ids {
18283                if should_unfold {
18284                    self.unfold_buffer(buffer_id, cx);
18285                } else {
18286                    self.fold_buffer(buffer_id, cx);
18287                }
18288            }
18289        }
18290    }
18291
18292    pub fn toggle_fold_recursive(
18293        &mut self,
18294        _: &actions::ToggleFoldRecursive,
18295        window: &mut Window,
18296        cx: &mut Context<Self>,
18297    ) {
18298        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
18299
18300        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18301        let range = if selection.is_empty() {
18302            let point = selection.head().to_display_point(&display_map);
18303            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
18304            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
18305                .to_point(&display_map);
18306            start..end
18307        } else {
18308            selection.range()
18309        };
18310        if display_map.folds_in_range(range).next().is_some() {
18311            self.unfold_recursive(&Default::default(), window, cx)
18312        } else {
18313            self.fold_recursive(&Default::default(), window, cx)
18314        }
18315    }
18316
18317    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
18318        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18319            let mut to_fold = Vec::new();
18320            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18321            let selections = self.selections.all_adjusted(&display_map);
18322
18323            for selection in selections {
18324                let range = selection.range().sorted();
18325                let buffer_start_row = range.start.row;
18326
18327                if range.start.row != range.end.row {
18328                    let mut found = false;
18329                    let mut row = range.start.row;
18330                    while row <= range.end.row {
18331                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
18332                        {
18333                            found = true;
18334                            row = crease.range().end.row + 1;
18335                            to_fold.push(crease);
18336                        } else {
18337                            row += 1
18338                        }
18339                    }
18340                    if found {
18341                        continue;
18342                    }
18343                }
18344
18345                for row in (0..=range.start.row).rev() {
18346                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
18347                        && crease.range().end.row >= buffer_start_row
18348                    {
18349                        to_fold.push(crease);
18350                        if row <= range.start.row {
18351                            break;
18352                        }
18353                    }
18354                }
18355            }
18356
18357            self.fold_creases(to_fold, true, window, cx);
18358        } else {
18359            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18360            let buffer_ids = self
18361                .selections
18362                .disjoint_anchor_ranges()
18363                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18364                .collect::<HashSet<_>>();
18365            for buffer_id in buffer_ids {
18366                self.fold_buffer(buffer_id, cx);
18367            }
18368        }
18369    }
18370
18371    pub fn toggle_fold_all(
18372        &mut self,
18373        _: &actions::ToggleFoldAll,
18374        window: &mut Window,
18375        cx: &mut Context<Self>,
18376    ) {
18377        if self.buffer.read(cx).is_singleton() {
18378            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18379            let has_folds = display_map
18380                .folds_in_range(0..display_map.buffer_snapshot().len())
18381                .next()
18382                .is_some();
18383
18384            if has_folds {
18385                self.unfold_all(&actions::UnfoldAll, window, cx);
18386            } else {
18387                self.fold_all(&actions::FoldAll, window, cx);
18388            }
18389        } else {
18390            let buffer_ids = self.buffer.read(cx).excerpt_buffer_ids();
18391            let should_unfold = buffer_ids
18392                .iter()
18393                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
18394
18395            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
18396                editor
18397                    .update_in(cx, |editor, _, cx| {
18398                        for buffer_id in buffer_ids {
18399                            if should_unfold {
18400                                editor.unfold_buffer(buffer_id, cx);
18401                            } else {
18402                                editor.fold_buffer(buffer_id, cx);
18403                            }
18404                        }
18405                    })
18406                    .ok();
18407            });
18408        }
18409    }
18410
18411    fn fold_at_level(
18412        &mut self,
18413        fold_at: &FoldAtLevel,
18414        window: &mut Window,
18415        cx: &mut Context<Self>,
18416    ) {
18417        if !self.buffer.read(cx).is_singleton() {
18418            return;
18419        }
18420
18421        let fold_at_level = fold_at.0;
18422        let snapshot = self.buffer.read(cx).snapshot(cx);
18423        let mut to_fold = Vec::new();
18424        let mut stack = vec![(0, snapshot.max_row().0, 1)];
18425
18426        let row_ranges_to_keep: Vec<Range<u32>> = self
18427            .selections
18428            .all::<Point>(&self.display_snapshot(cx))
18429            .into_iter()
18430            .map(|sel| sel.start.row..sel.end.row)
18431            .collect();
18432
18433        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
18434            while start_row < end_row {
18435                match self
18436                    .snapshot(window, cx)
18437                    .crease_for_buffer_row(MultiBufferRow(start_row))
18438                {
18439                    Some(crease) => {
18440                        let nested_start_row = crease.range().start.row + 1;
18441                        let nested_end_row = crease.range().end.row;
18442
18443                        if current_level < fold_at_level {
18444                            stack.push((nested_start_row, nested_end_row, current_level + 1));
18445                        } else if current_level == fold_at_level {
18446                            // Fold iff there is no selection completely contained within the fold region
18447                            if !row_ranges_to_keep.iter().any(|selection| {
18448                                selection.end >= nested_start_row
18449                                    && selection.start <= nested_end_row
18450                            }) {
18451                                to_fold.push(crease);
18452                            }
18453                        }
18454
18455                        start_row = nested_end_row + 1;
18456                    }
18457                    None => start_row += 1,
18458                }
18459            }
18460        }
18461
18462        self.fold_creases(to_fold, true, window, cx);
18463    }
18464
18465    pub fn fold_at_level_1(
18466        &mut self,
18467        _: &actions::FoldAtLevel1,
18468        window: &mut Window,
18469        cx: &mut Context<Self>,
18470    ) {
18471        self.fold_at_level(&actions::FoldAtLevel(1), window, cx);
18472    }
18473
18474    pub fn fold_at_level_2(
18475        &mut self,
18476        _: &actions::FoldAtLevel2,
18477        window: &mut Window,
18478        cx: &mut Context<Self>,
18479    ) {
18480        self.fold_at_level(&actions::FoldAtLevel(2), window, cx);
18481    }
18482
18483    pub fn fold_at_level_3(
18484        &mut self,
18485        _: &actions::FoldAtLevel3,
18486        window: &mut Window,
18487        cx: &mut Context<Self>,
18488    ) {
18489        self.fold_at_level(&actions::FoldAtLevel(3), window, cx);
18490    }
18491
18492    pub fn fold_at_level_4(
18493        &mut self,
18494        _: &actions::FoldAtLevel4,
18495        window: &mut Window,
18496        cx: &mut Context<Self>,
18497    ) {
18498        self.fold_at_level(&actions::FoldAtLevel(4), window, cx);
18499    }
18500
18501    pub fn fold_at_level_5(
18502        &mut self,
18503        _: &actions::FoldAtLevel5,
18504        window: &mut Window,
18505        cx: &mut Context<Self>,
18506    ) {
18507        self.fold_at_level(&actions::FoldAtLevel(5), window, cx);
18508    }
18509
18510    pub fn fold_at_level_6(
18511        &mut self,
18512        _: &actions::FoldAtLevel6,
18513        window: &mut Window,
18514        cx: &mut Context<Self>,
18515    ) {
18516        self.fold_at_level(&actions::FoldAtLevel(6), window, cx);
18517    }
18518
18519    pub fn fold_at_level_7(
18520        &mut self,
18521        _: &actions::FoldAtLevel7,
18522        window: &mut Window,
18523        cx: &mut Context<Self>,
18524    ) {
18525        self.fold_at_level(&actions::FoldAtLevel(7), window, cx);
18526    }
18527
18528    pub fn fold_at_level_8(
18529        &mut self,
18530        _: &actions::FoldAtLevel8,
18531        window: &mut Window,
18532        cx: &mut Context<Self>,
18533    ) {
18534        self.fold_at_level(&actions::FoldAtLevel(8), window, cx);
18535    }
18536
18537    pub fn fold_at_level_9(
18538        &mut self,
18539        _: &actions::FoldAtLevel9,
18540        window: &mut Window,
18541        cx: &mut Context<Self>,
18542    ) {
18543        self.fold_at_level(&actions::FoldAtLevel(9), window, cx);
18544    }
18545
18546    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
18547        if self.buffer.read(cx).is_singleton() {
18548            let mut fold_ranges = Vec::new();
18549            let snapshot = self.buffer.read(cx).snapshot(cx);
18550
18551            for row in 0..snapshot.max_row().0 {
18552                if let Some(foldable_range) = self
18553                    .snapshot(window, cx)
18554                    .crease_for_buffer_row(MultiBufferRow(row))
18555                {
18556                    fold_ranges.push(foldable_range);
18557                }
18558            }
18559
18560            self.fold_creases(fold_ranges, true, window, cx);
18561        } else {
18562            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
18563                editor
18564                    .update_in(cx, |editor, _, cx| {
18565                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
18566                            editor.fold_buffer(buffer_id, cx);
18567                        }
18568                    })
18569                    .ok();
18570            });
18571        }
18572    }
18573
18574    pub fn fold_function_bodies(
18575        &mut self,
18576        _: &actions::FoldFunctionBodies,
18577        window: &mut Window,
18578        cx: &mut Context<Self>,
18579    ) {
18580        let snapshot = self.buffer.read(cx).snapshot(cx);
18581
18582        let ranges = snapshot
18583            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
18584            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
18585            .collect::<Vec<_>>();
18586
18587        let creases = ranges
18588            .into_iter()
18589            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
18590            .collect();
18591
18592        self.fold_creases(creases, true, window, cx);
18593    }
18594
18595    pub fn fold_recursive(
18596        &mut self,
18597        _: &actions::FoldRecursive,
18598        window: &mut Window,
18599        cx: &mut Context<Self>,
18600    ) {
18601        let mut to_fold = Vec::new();
18602        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18603        let selections = self.selections.all_adjusted(&display_map);
18604
18605        for selection in selections {
18606            let range = selection.range().sorted();
18607            let buffer_start_row = range.start.row;
18608
18609            if range.start.row != range.end.row {
18610                let mut found = false;
18611                for row in range.start.row..=range.end.row {
18612                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
18613                        found = true;
18614                        to_fold.push(crease);
18615                    }
18616                }
18617                if found {
18618                    continue;
18619                }
18620            }
18621
18622            for row in (0..=range.start.row).rev() {
18623                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
18624                    if crease.range().end.row >= buffer_start_row {
18625                        to_fold.push(crease);
18626                    } else {
18627                        break;
18628                    }
18629                }
18630            }
18631        }
18632
18633        self.fold_creases(to_fold, true, window, cx);
18634    }
18635
18636    pub fn fold_at(
18637        &mut self,
18638        buffer_row: MultiBufferRow,
18639        window: &mut Window,
18640        cx: &mut Context<Self>,
18641    ) {
18642        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18643
18644        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
18645            let autoscroll = self
18646                .selections
18647                .all::<Point>(&display_map)
18648                .iter()
18649                .any(|selection| crease.range().overlaps(&selection.range()));
18650
18651            self.fold_creases(vec![crease], autoscroll, window, cx);
18652        }
18653    }
18654
18655    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
18656        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18657            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18658            let buffer = display_map.buffer_snapshot();
18659            let selections = self.selections.all::<Point>(&display_map);
18660            let ranges = selections
18661                .iter()
18662                .map(|s| {
18663                    let range = s.display_range(&display_map).sorted();
18664                    let mut start = range.start.to_point(&display_map);
18665                    let mut end = range.end.to_point(&display_map);
18666                    start.column = 0;
18667                    end.column = buffer.line_len(MultiBufferRow(end.row));
18668                    start..end
18669                })
18670                .collect::<Vec<_>>();
18671
18672            self.unfold_ranges(&ranges, true, true, cx);
18673        } else {
18674            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18675            let buffer_ids = self
18676                .selections
18677                .disjoint_anchor_ranges()
18678                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18679                .collect::<HashSet<_>>();
18680            for buffer_id in buffer_ids {
18681                self.unfold_buffer(buffer_id, cx);
18682            }
18683        }
18684    }
18685
18686    pub fn unfold_recursive(
18687        &mut self,
18688        _: &UnfoldRecursive,
18689        _window: &mut Window,
18690        cx: &mut Context<Self>,
18691    ) {
18692        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18693        let selections = self.selections.all::<Point>(&display_map);
18694        let ranges = selections
18695            .iter()
18696            .map(|s| {
18697                let mut range = s.display_range(&display_map).sorted();
18698                *range.start.column_mut() = 0;
18699                *range.end.column_mut() = display_map.line_len(range.end.row());
18700                let start = range.start.to_point(&display_map);
18701                let end = range.end.to_point(&display_map);
18702                start..end
18703            })
18704            .collect::<Vec<_>>();
18705
18706        self.unfold_ranges(&ranges, true, true, cx);
18707    }
18708
18709    pub fn unfold_at(
18710        &mut self,
18711        buffer_row: MultiBufferRow,
18712        _window: &mut Window,
18713        cx: &mut Context<Self>,
18714    ) {
18715        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18716
18717        let intersection_range = Point::new(buffer_row.0, 0)
18718            ..Point::new(
18719                buffer_row.0,
18720                display_map.buffer_snapshot().line_len(buffer_row),
18721            );
18722
18723        let autoscroll = self
18724            .selections
18725            .all::<Point>(&display_map)
18726            .iter()
18727            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
18728
18729        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
18730    }
18731
18732    pub fn unfold_all(
18733        &mut self,
18734        _: &actions::UnfoldAll,
18735        _window: &mut Window,
18736        cx: &mut Context<Self>,
18737    ) {
18738        if self.buffer.read(cx).is_singleton() {
18739            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18740            self.unfold_ranges(&[0..display_map.buffer_snapshot().len()], true, true, cx);
18741        } else {
18742            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
18743                editor
18744                    .update(cx, |editor, cx| {
18745                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
18746                            editor.unfold_buffer(buffer_id, cx);
18747                        }
18748                    })
18749                    .ok();
18750            });
18751        }
18752    }
18753
18754    pub fn fold_selected_ranges(
18755        &mut self,
18756        _: &FoldSelectedRanges,
18757        window: &mut Window,
18758        cx: &mut Context<Self>,
18759    ) {
18760        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18761        let selections = self.selections.all_adjusted(&display_map);
18762        let ranges = selections
18763            .into_iter()
18764            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
18765            .collect::<Vec<_>>();
18766        self.fold_creases(ranges, true, window, cx);
18767    }
18768
18769    pub fn fold_ranges<T: ToOffset + Clone>(
18770        &mut self,
18771        ranges: Vec<Range<T>>,
18772        auto_scroll: bool,
18773        window: &mut Window,
18774        cx: &mut Context<Self>,
18775    ) {
18776        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18777        let ranges = ranges
18778            .into_iter()
18779            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
18780            .collect::<Vec<_>>();
18781        self.fold_creases(ranges, auto_scroll, window, cx);
18782    }
18783
18784    pub fn fold_creases<T: ToOffset + Clone>(
18785        &mut self,
18786        creases: Vec<Crease<T>>,
18787        auto_scroll: bool,
18788        _window: &mut Window,
18789        cx: &mut Context<Self>,
18790    ) {
18791        if creases.is_empty() {
18792            return;
18793        }
18794
18795        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
18796
18797        if auto_scroll {
18798            self.request_autoscroll(Autoscroll::fit(), cx);
18799        }
18800
18801        cx.notify();
18802
18803        self.scrollbar_marker_state.dirty = true;
18804        self.folds_did_change(cx);
18805    }
18806
18807    /// Removes any folds whose ranges intersect any of the given ranges.
18808    pub fn unfold_ranges<T: ToOffset + Clone>(
18809        &mut self,
18810        ranges: &[Range<T>],
18811        inclusive: bool,
18812        auto_scroll: bool,
18813        cx: &mut Context<Self>,
18814    ) {
18815        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
18816            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
18817        });
18818        self.folds_did_change(cx);
18819    }
18820
18821    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18822        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
18823            return;
18824        }
18825        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
18826        self.display_map.update(cx, |display_map, cx| {
18827            display_map.fold_buffers([buffer_id], cx)
18828        });
18829        cx.emit(EditorEvent::BufferFoldToggled {
18830            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
18831            folded: true,
18832        });
18833        cx.notify();
18834    }
18835
18836    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18837        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
18838            return;
18839        }
18840        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
18841        self.display_map.update(cx, |display_map, cx| {
18842            display_map.unfold_buffers([buffer_id], cx);
18843        });
18844        cx.emit(EditorEvent::BufferFoldToggled {
18845            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
18846            folded: false,
18847        });
18848        cx.notify();
18849    }
18850
18851    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
18852        self.display_map.read(cx).is_buffer_folded(buffer)
18853    }
18854
18855    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
18856        self.display_map.read(cx).folded_buffers()
18857    }
18858
18859    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18860        self.display_map.update(cx, |display_map, cx| {
18861            display_map.disable_header_for_buffer(buffer_id, cx);
18862        });
18863        cx.notify();
18864    }
18865
18866    /// Removes any folds with the given ranges.
18867    pub fn remove_folds_with_type<T: ToOffset + Clone>(
18868        &mut self,
18869        ranges: &[Range<T>],
18870        type_id: TypeId,
18871        auto_scroll: bool,
18872        cx: &mut Context<Self>,
18873    ) {
18874        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
18875            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
18876        });
18877        self.folds_did_change(cx);
18878    }
18879
18880    fn remove_folds_with<T: ToOffset + Clone>(
18881        &mut self,
18882        ranges: &[Range<T>],
18883        auto_scroll: bool,
18884        cx: &mut Context<Self>,
18885        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
18886    ) {
18887        if ranges.is_empty() {
18888            return;
18889        }
18890
18891        let mut buffers_affected = HashSet::default();
18892        let multi_buffer = self.buffer().read(cx);
18893        for range in ranges {
18894            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
18895                buffers_affected.insert(buffer.read(cx).remote_id());
18896            };
18897        }
18898
18899        self.display_map.update(cx, update);
18900
18901        if auto_scroll {
18902            self.request_autoscroll(Autoscroll::fit(), cx);
18903        }
18904
18905        cx.notify();
18906        self.scrollbar_marker_state.dirty = true;
18907        self.active_indent_guides_state.dirty = true;
18908    }
18909
18910    pub fn update_renderer_widths(
18911        &mut self,
18912        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
18913        cx: &mut Context<Self>,
18914    ) -> bool {
18915        self.display_map
18916            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
18917    }
18918
18919    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
18920        self.display_map.read(cx).fold_placeholder.clone()
18921    }
18922
18923    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
18924        self.buffer.update(cx, |buffer, cx| {
18925            buffer.set_all_diff_hunks_expanded(cx);
18926        });
18927    }
18928
18929    pub fn expand_all_diff_hunks(
18930        &mut self,
18931        _: &ExpandAllDiffHunks,
18932        _window: &mut Window,
18933        cx: &mut Context<Self>,
18934    ) {
18935        self.buffer.update(cx, |buffer, cx| {
18936            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
18937        });
18938    }
18939
18940    pub fn collapse_all_diff_hunks(
18941        &mut self,
18942        _: &CollapseAllDiffHunks,
18943        _window: &mut Window,
18944        cx: &mut Context<Self>,
18945    ) {
18946        self.buffer.update(cx, |buffer, cx| {
18947            buffer.collapse_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
18948        });
18949    }
18950
18951    pub fn toggle_selected_diff_hunks(
18952        &mut self,
18953        _: &ToggleSelectedDiffHunks,
18954        _window: &mut Window,
18955        cx: &mut Context<Self>,
18956    ) {
18957        let ranges: Vec<_> = self
18958            .selections
18959            .disjoint_anchors()
18960            .iter()
18961            .map(|s| s.range())
18962            .collect();
18963        self.toggle_diff_hunks_in_ranges(ranges, cx);
18964    }
18965
18966    pub fn diff_hunks_in_ranges<'a>(
18967        &'a self,
18968        ranges: &'a [Range<Anchor>],
18969        buffer: &'a MultiBufferSnapshot,
18970    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
18971        ranges.iter().flat_map(move |range| {
18972            let end_excerpt_id = range.end.excerpt_id;
18973            let range = range.to_point(buffer);
18974            let mut peek_end = range.end;
18975            if range.end.row < buffer.max_row().0 {
18976                peek_end = Point::new(range.end.row + 1, 0);
18977            }
18978            buffer
18979                .diff_hunks_in_range(range.start..peek_end)
18980                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
18981        })
18982    }
18983
18984    pub fn has_stageable_diff_hunks_in_ranges(
18985        &self,
18986        ranges: &[Range<Anchor>],
18987        snapshot: &MultiBufferSnapshot,
18988    ) -> bool {
18989        let mut hunks = self.diff_hunks_in_ranges(ranges, snapshot);
18990        hunks.any(|hunk| hunk.status().has_secondary_hunk())
18991    }
18992
18993    pub fn toggle_staged_selected_diff_hunks(
18994        &mut self,
18995        _: &::git::ToggleStaged,
18996        _: &mut Window,
18997        cx: &mut Context<Self>,
18998    ) {
18999        let snapshot = self.buffer.read(cx).snapshot(cx);
19000        let ranges: Vec<_> = self
19001            .selections
19002            .disjoint_anchors()
19003            .iter()
19004            .map(|s| s.range())
19005            .collect();
19006        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
19007        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
19008    }
19009
19010    pub fn set_render_diff_hunk_controls(
19011        &mut self,
19012        render_diff_hunk_controls: RenderDiffHunkControlsFn,
19013        cx: &mut Context<Self>,
19014    ) {
19015        self.render_diff_hunk_controls = render_diff_hunk_controls;
19016        cx.notify();
19017    }
19018
19019    pub fn stage_and_next(
19020        &mut self,
19021        _: &::git::StageAndNext,
19022        window: &mut Window,
19023        cx: &mut Context<Self>,
19024    ) {
19025        self.do_stage_or_unstage_and_next(true, window, cx);
19026    }
19027
19028    pub fn unstage_and_next(
19029        &mut self,
19030        _: &::git::UnstageAndNext,
19031        window: &mut Window,
19032        cx: &mut Context<Self>,
19033    ) {
19034        self.do_stage_or_unstage_and_next(false, window, cx);
19035    }
19036
19037    pub fn stage_or_unstage_diff_hunks(
19038        &mut self,
19039        stage: bool,
19040        ranges: Vec<Range<Anchor>>,
19041        cx: &mut Context<Self>,
19042    ) {
19043        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
19044        cx.spawn(async move |this, cx| {
19045            task.await?;
19046            this.update(cx, |this, cx| {
19047                let snapshot = this.buffer.read(cx).snapshot(cx);
19048                let chunk_by = this
19049                    .diff_hunks_in_ranges(&ranges, &snapshot)
19050                    .chunk_by(|hunk| hunk.buffer_id);
19051                for (buffer_id, hunks) in &chunk_by {
19052                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
19053                }
19054            })
19055        })
19056        .detach_and_log_err(cx);
19057    }
19058
19059    fn save_buffers_for_ranges_if_needed(
19060        &mut self,
19061        ranges: &[Range<Anchor>],
19062        cx: &mut Context<Editor>,
19063    ) -> Task<Result<()>> {
19064        let multibuffer = self.buffer.read(cx);
19065        let snapshot = multibuffer.read(cx);
19066        let buffer_ids: HashSet<_> = ranges
19067            .iter()
19068            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
19069            .collect();
19070        drop(snapshot);
19071
19072        let mut buffers = HashSet::default();
19073        for buffer_id in buffer_ids {
19074            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
19075                let buffer = buffer_entity.read(cx);
19076                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
19077                {
19078                    buffers.insert(buffer_entity);
19079                }
19080            }
19081        }
19082
19083        if let Some(project) = &self.project {
19084            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
19085        } else {
19086            Task::ready(Ok(()))
19087        }
19088    }
19089
19090    fn do_stage_or_unstage_and_next(
19091        &mut self,
19092        stage: bool,
19093        window: &mut Window,
19094        cx: &mut Context<Self>,
19095    ) {
19096        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
19097
19098        if ranges.iter().any(|range| range.start != range.end) {
19099            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
19100            return;
19101        }
19102
19103        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
19104        let snapshot = self.snapshot(window, cx);
19105        let position = self
19106            .selections
19107            .newest::<Point>(&snapshot.display_snapshot)
19108            .head();
19109        let mut row = snapshot
19110            .buffer_snapshot()
19111            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
19112            .find(|hunk| hunk.row_range.start.0 > position.row)
19113            .map(|hunk| hunk.row_range.start);
19114
19115        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
19116        // Outside of the project diff editor, wrap around to the beginning.
19117        if !all_diff_hunks_expanded {
19118            row = row.or_else(|| {
19119                snapshot
19120                    .buffer_snapshot()
19121                    .diff_hunks_in_range(Point::zero()..position)
19122                    .find(|hunk| hunk.row_range.end.0 < position.row)
19123                    .map(|hunk| hunk.row_range.start)
19124            });
19125        }
19126
19127        if let Some(row) = row {
19128            let destination = Point::new(row.0, 0);
19129            let autoscroll = Autoscroll::center();
19130
19131            self.unfold_ranges(&[destination..destination], false, false, cx);
19132            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
19133                s.select_ranges([destination..destination]);
19134            });
19135        }
19136    }
19137
19138    fn do_stage_or_unstage(
19139        &self,
19140        stage: bool,
19141        buffer_id: BufferId,
19142        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
19143        cx: &mut App,
19144    ) -> Option<()> {
19145        let project = self.project()?;
19146        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
19147        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
19148        let buffer_snapshot = buffer.read(cx).snapshot();
19149        let file_exists = buffer_snapshot
19150            .file()
19151            .is_some_and(|file| file.disk_state().exists());
19152        diff.update(cx, |diff, cx| {
19153            diff.stage_or_unstage_hunks(
19154                stage,
19155                &hunks
19156                    .map(|hunk| buffer_diff::DiffHunk {
19157                        buffer_range: hunk.buffer_range,
19158                        diff_base_byte_range: hunk.diff_base_byte_range,
19159                        secondary_status: hunk.secondary_status,
19160                        range: Point::zero()..Point::zero(), // unused
19161                    })
19162                    .collect::<Vec<_>>(),
19163                &buffer_snapshot,
19164                file_exists,
19165                cx,
19166            )
19167        });
19168        None
19169    }
19170
19171    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
19172        let ranges: Vec<_> = self
19173            .selections
19174            .disjoint_anchors()
19175            .iter()
19176            .map(|s| s.range())
19177            .collect();
19178        self.buffer
19179            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
19180    }
19181
19182    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
19183        self.buffer.update(cx, |buffer, cx| {
19184            let ranges = vec![Anchor::min()..Anchor::max()];
19185            if !buffer.all_diff_hunks_expanded()
19186                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
19187            {
19188                buffer.collapse_diff_hunks(ranges, cx);
19189                true
19190            } else {
19191                false
19192            }
19193        })
19194    }
19195
19196    fn toggle_diff_hunks_in_ranges(
19197        &mut self,
19198        ranges: Vec<Range<Anchor>>,
19199        cx: &mut Context<Editor>,
19200    ) {
19201        self.buffer.update(cx, |buffer, cx| {
19202            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
19203            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
19204        })
19205    }
19206
19207    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
19208        self.buffer.update(cx, |buffer, cx| {
19209            let snapshot = buffer.snapshot(cx);
19210            let excerpt_id = range.end.excerpt_id;
19211            let point_range = range.to_point(&snapshot);
19212            let expand = !buffer.single_hunk_is_expanded(range, cx);
19213            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
19214        })
19215    }
19216
19217    pub(crate) fn apply_all_diff_hunks(
19218        &mut self,
19219        _: &ApplyAllDiffHunks,
19220        window: &mut Window,
19221        cx: &mut Context<Self>,
19222    ) {
19223        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19224
19225        let buffers = self.buffer.read(cx).all_buffers();
19226        for branch_buffer in buffers {
19227            branch_buffer.update(cx, |branch_buffer, cx| {
19228                branch_buffer.merge_into_base(Vec::new(), cx);
19229            });
19230        }
19231
19232        if let Some(project) = self.project.clone() {
19233            self.save(
19234                SaveOptions {
19235                    format: true,
19236                    autosave: false,
19237                },
19238                project,
19239                window,
19240                cx,
19241            )
19242            .detach_and_log_err(cx);
19243        }
19244    }
19245
19246    pub(crate) fn apply_selected_diff_hunks(
19247        &mut self,
19248        _: &ApplyDiffHunk,
19249        window: &mut Window,
19250        cx: &mut Context<Self>,
19251    ) {
19252        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19253        let snapshot = self.snapshot(window, cx);
19254        let hunks = snapshot.hunks_for_ranges(
19255            self.selections
19256                .all(&snapshot.display_snapshot)
19257                .into_iter()
19258                .map(|selection| selection.range()),
19259        );
19260        let mut ranges_by_buffer = HashMap::default();
19261        self.transact(window, cx, |editor, _window, cx| {
19262            for hunk in hunks {
19263                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
19264                    ranges_by_buffer
19265                        .entry(buffer.clone())
19266                        .or_insert_with(Vec::new)
19267                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
19268                }
19269            }
19270
19271            for (buffer, ranges) in ranges_by_buffer {
19272                buffer.update(cx, |buffer, cx| {
19273                    buffer.merge_into_base(ranges, cx);
19274                });
19275            }
19276        });
19277
19278        if let Some(project) = self.project.clone() {
19279            self.save(
19280                SaveOptions {
19281                    format: true,
19282                    autosave: false,
19283                },
19284                project,
19285                window,
19286                cx,
19287            )
19288            .detach_and_log_err(cx);
19289        }
19290    }
19291
19292    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
19293        if hovered != self.gutter_hovered {
19294            self.gutter_hovered = hovered;
19295            cx.notify();
19296        }
19297    }
19298
19299    pub fn insert_blocks(
19300        &mut self,
19301        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
19302        autoscroll: Option<Autoscroll>,
19303        cx: &mut Context<Self>,
19304    ) -> Vec<CustomBlockId> {
19305        let blocks = self
19306            .display_map
19307            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
19308        if let Some(autoscroll) = autoscroll {
19309            self.request_autoscroll(autoscroll, cx);
19310        }
19311        cx.notify();
19312        blocks
19313    }
19314
19315    pub fn resize_blocks(
19316        &mut self,
19317        heights: HashMap<CustomBlockId, u32>,
19318        autoscroll: Option<Autoscroll>,
19319        cx: &mut Context<Self>,
19320    ) {
19321        self.display_map
19322            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
19323        if let Some(autoscroll) = autoscroll {
19324            self.request_autoscroll(autoscroll, cx);
19325        }
19326        cx.notify();
19327    }
19328
19329    pub fn replace_blocks(
19330        &mut self,
19331        renderers: HashMap<CustomBlockId, RenderBlock>,
19332        autoscroll: Option<Autoscroll>,
19333        cx: &mut Context<Self>,
19334    ) {
19335        self.display_map
19336            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
19337        if let Some(autoscroll) = autoscroll {
19338            self.request_autoscroll(autoscroll, cx);
19339        }
19340        cx.notify();
19341    }
19342
19343    pub fn remove_blocks(
19344        &mut self,
19345        block_ids: HashSet<CustomBlockId>,
19346        autoscroll: Option<Autoscroll>,
19347        cx: &mut Context<Self>,
19348    ) {
19349        self.display_map.update(cx, |display_map, cx| {
19350            display_map.remove_blocks(block_ids, cx)
19351        });
19352        if let Some(autoscroll) = autoscroll {
19353            self.request_autoscroll(autoscroll, cx);
19354        }
19355        cx.notify();
19356    }
19357
19358    pub fn row_for_block(
19359        &self,
19360        block_id: CustomBlockId,
19361        cx: &mut Context<Self>,
19362    ) -> Option<DisplayRow> {
19363        self.display_map
19364            .update(cx, |map, cx| map.row_for_block(block_id, cx))
19365    }
19366
19367    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
19368        self.focused_block = Some(focused_block);
19369    }
19370
19371    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
19372        self.focused_block.take()
19373    }
19374
19375    pub fn insert_creases(
19376        &mut self,
19377        creases: impl IntoIterator<Item = Crease<Anchor>>,
19378        cx: &mut Context<Self>,
19379    ) -> Vec<CreaseId> {
19380        self.display_map
19381            .update(cx, |map, cx| map.insert_creases(creases, cx))
19382    }
19383
19384    pub fn remove_creases(
19385        &mut self,
19386        ids: impl IntoIterator<Item = CreaseId>,
19387        cx: &mut Context<Self>,
19388    ) -> Vec<(CreaseId, Range<Anchor>)> {
19389        self.display_map
19390            .update(cx, |map, cx| map.remove_creases(ids, cx))
19391    }
19392
19393    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
19394        self.display_map
19395            .update(cx, |map, cx| map.snapshot(cx))
19396            .longest_row()
19397    }
19398
19399    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
19400        self.display_map
19401            .update(cx, |map, cx| map.snapshot(cx))
19402            .max_point()
19403    }
19404
19405    pub fn text(&self, cx: &App) -> String {
19406        self.buffer.read(cx).read(cx).text()
19407    }
19408
19409    pub fn is_empty(&self, cx: &App) -> bool {
19410        self.buffer.read(cx).read(cx).is_empty()
19411    }
19412
19413    pub fn text_option(&self, cx: &App) -> Option<String> {
19414        let text = self.text(cx);
19415        let text = text.trim();
19416
19417        if text.is_empty() {
19418            return None;
19419        }
19420
19421        Some(text.to_string())
19422    }
19423
19424    pub fn set_text(
19425        &mut self,
19426        text: impl Into<Arc<str>>,
19427        window: &mut Window,
19428        cx: &mut Context<Self>,
19429    ) {
19430        self.transact(window, cx, |this, _, cx| {
19431            this.buffer
19432                .read(cx)
19433                .as_singleton()
19434                .expect("you can only call set_text on editors for singleton buffers")
19435                .update(cx, |buffer, cx| buffer.set_text(text, cx));
19436        });
19437    }
19438
19439    pub fn display_text(&self, cx: &mut App) -> String {
19440        self.display_map
19441            .update(cx, |map, cx| map.snapshot(cx))
19442            .text()
19443    }
19444
19445    fn create_minimap(
19446        &self,
19447        minimap_settings: MinimapSettings,
19448        window: &mut Window,
19449        cx: &mut Context<Self>,
19450    ) -> Option<Entity<Self>> {
19451        (minimap_settings.minimap_enabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton)
19452            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
19453    }
19454
19455    fn initialize_new_minimap(
19456        &self,
19457        minimap_settings: MinimapSettings,
19458        window: &mut Window,
19459        cx: &mut Context<Self>,
19460    ) -> Entity<Self> {
19461        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
19462
19463        let mut minimap = Editor::new_internal(
19464            EditorMode::Minimap {
19465                parent: cx.weak_entity(),
19466            },
19467            self.buffer.clone(),
19468            None,
19469            Some(self.display_map.clone()),
19470            window,
19471            cx,
19472        );
19473        minimap.scroll_manager.clone_state(&self.scroll_manager);
19474        minimap.set_text_style_refinement(TextStyleRefinement {
19475            font_size: Some(MINIMAP_FONT_SIZE),
19476            font_weight: Some(MINIMAP_FONT_WEIGHT),
19477            ..Default::default()
19478        });
19479        minimap.update_minimap_configuration(minimap_settings, cx);
19480        cx.new(|_| minimap)
19481    }
19482
19483    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
19484        let current_line_highlight = minimap_settings
19485            .current_line_highlight
19486            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
19487        self.set_current_line_highlight(Some(current_line_highlight));
19488    }
19489
19490    pub fn minimap(&self) -> Option<&Entity<Self>> {
19491        self.minimap
19492            .as_ref()
19493            .filter(|_| self.minimap_visibility.visible())
19494    }
19495
19496    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
19497        let mut wrap_guides = smallvec![];
19498
19499        if self.show_wrap_guides == Some(false) {
19500            return wrap_guides;
19501        }
19502
19503        let settings = self.buffer.read(cx).language_settings(cx);
19504        if settings.show_wrap_guides {
19505            match self.soft_wrap_mode(cx) {
19506                SoftWrap::Column(soft_wrap) => {
19507                    wrap_guides.push((soft_wrap as usize, true));
19508                }
19509                SoftWrap::Bounded(soft_wrap) => {
19510                    wrap_guides.push((soft_wrap as usize, true));
19511                }
19512                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
19513            }
19514            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
19515        }
19516
19517        wrap_guides
19518    }
19519
19520    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
19521        let settings = self.buffer.read(cx).language_settings(cx);
19522        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
19523        match mode {
19524            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
19525                SoftWrap::None
19526            }
19527            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
19528            language_settings::SoftWrap::PreferredLineLength => {
19529                SoftWrap::Column(settings.preferred_line_length)
19530            }
19531            language_settings::SoftWrap::Bounded => {
19532                SoftWrap::Bounded(settings.preferred_line_length)
19533            }
19534        }
19535    }
19536
19537    pub fn set_soft_wrap_mode(
19538        &mut self,
19539        mode: language_settings::SoftWrap,
19540
19541        cx: &mut Context<Self>,
19542    ) {
19543        self.soft_wrap_mode_override = Some(mode);
19544        cx.notify();
19545    }
19546
19547    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
19548        self.hard_wrap = hard_wrap;
19549        cx.notify();
19550    }
19551
19552    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
19553        self.text_style_refinement = Some(style);
19554    }
19555
19556    /// called by the Element so we know what style we were most recently rendered with.
19557    pub fn set_style(&mut self, style: EditorStyle, window: &mut Window, cx: &mut Context<Self>) {
19558        // We intentionally do not inform the display map about the minimap style
19559        // so that wrapping is not recalculated and stays consistent for the editor
19560        // and its linked minimap.
19561        if !self.mode.is_minimap() {
19562            let font = style.text.font();
19563            let font_size = style.text.font_size.to_pixels(window.rem_size());
19564            let display_map = self
19565                .placeholder_display_map
19566                .as_ref()
19567                .filter(|_| self.is_empty(cx))
19568                .unwrap_or(&self.display_map);
19569
19570            display_map.update(cx, |map, cx| map.set_font(font, font_size, cx));
19571        }
19572        self.style = Some(style);
19573    }
19574
19575    pub fn style(&self) -> Option<&EditorStyle> {
19576        self.style.as_ref()
19577    }
19578
19579    // Called by the element. This method is not designed to be called outside of the editor
19580    // element's layout code because it does not notify when rewrapping is computed synchronously.
19581    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
19582        if self.is_empty(cx) {
19583            self.placeholder_display_map
19584                .as_ref()
19585                .map_or(false, |display_map| {
19586                    display_map.update(cx, |map, cx| map.set_wrap_width(width, cx))
19587                })
19588        } else {
19589            self.display_map
19590                .update(cx, |map, cx| map.set_wrap_width(width, cx))
19591        }
19592    }
19593
19594    pub fn set_soft_wrap(&mut self) {
19595        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
19596    }
19597
19598    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
19599        if self.soft_wrap_mode_override.is_some() {
19600            self.soft_wrap_mode_override.take();
19601        } else {
19602            let soft_wrap = match self.soft_wrap_mode(cx) {
19603                SoftWrap::GitDiff => return,
19604                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
19605                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
19606                    language_settings::SoftWrap::None
19607                }
19608            };
19609            self.soft_wrap_mode_override = Some(soft_wrap);
19610        }
19611        cx.notify();
19612    }
19613
19614    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
19615        let Some(workspace) = self.workspace() else {
19616            return;
19617        };
19618        let fs = workspace.read(cx).app_state().fs.clone();
19619        let current_show = TabBarSettings::get_global(cx).show;
19620        update_settings_file(fs, cx, move |setting, _| {
19621            setting.tab_bar.get_or_insert_default().show = Some(!current_show);
19622        });
19623    }
19624
19625    pub fn toggle_indent_guides(
19626        &mut self,
19627        _: &ToggleIndentGuides,
19628        _: &mut Window,
19629        cx: &mut Context<Self>,
19630    ) {
19631        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
19632            self.buffer
19633                .read(cx)
19634                .language_settings(cx)
19635                .indent_guides
19636                .enabled
19637        });
19638        self.show_indent_guides = Some(!currently_enabled);
19639        cx.notify();
19640    }
19641
19642    fn should_show_indent_guides(&self) -> Option<bool> {
19643        self.show_indent_guides
19644    }
19645
19646    pub fn toggle_line_numbers(
19647        &mut self,
19648        _: &ToggleLineNumbers,
19649        _: &mut Window,
19650        cx: &mut Context<Self>,
19651    ) {
19652        let mut editor_settings = EditorSettings::get_global(cx).clone();
19653        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
19654        EditorSettings::override_global(editor_settings, cx);
19655    }
19656
19657    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
19658        if let Some(show_line_numbers) = self.show_line_numbers {
19659            return show_line_numbers;
19660        }
19661        EditorSettings::get_global(cx).gutter.line_numbers
19662    }
19663
19664    pub fn relative_line_numbers(&self, cx: &mut App) -> RelativeLineNumbers {
19665        match (
19666            self.use_relative_line_numbers,
19667            EditorSettings::get_global(cx).relative_line_numbers,
19668        ) {
19669            (None, setting) => setting,
19670            (Some(false), _) => RelativeLineNumbers::Disabled,
19671            (Some(true), RelativeLineNumbers::Wrapped) => RelativeLineNumbers::Wrapped,
19672            (Some(true), _) => RelativeLineNumbers::Enabled,
19673        }
19674    }
19675
19676    pub fn toggle_relative_line_numbers(
19677        &mut self,
19678        _: &ToggleRelativeLineNumbers,
19679        _: &mut Window,
19680        cx: &mut Context<Self>,
19681    ) {
19682        let is_relative = self.relative_line_numbers(cx);
19683        self.set_relative_line_number(Some(!is_relative.enabled()), cx)
19684    }
19685
19686    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
19687        self.use_relative_line_numbers = is_relative;
19688        cx.notify();
19689    }
19690
19691    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
19692        self.show_gutter = show_gutter;
19693        cx.notify();
19694    }
19695
19696    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
19697        self.show_scrollbars = ScrollbarAxes {
19698            horizontal: show,
19699            vertical: show,
19700        };
19701        cx.notify();
19702    }
19703
19704    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
19705        self.show_scrollbars.vertical = show;
19706        cx.notify();
19707    }
19708
19709    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
19710        self.show_scrollbars.horizontal = show;
19711        cx.notify();
19712    }
19713
19714    pub fn set_minimap_visibility(
19715        &mut self,
19716        minimap_visibility: MinimapVisibility,
19717        window: &mut Window,
19718        cx: &mut Context<Self>,
19719    ) {
19720        if self.minimap_visibility != minimap_visibility {
19721            if minimap_visibility.visible() && self.minimap.is_none() {
19722                let minimap_settings = EditorSettings::get_global(cx).minimap;
19723                self.minimap =
19724                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
19725            }
19726            self.minimap_visibility = minimap_visibility;
19727            cx.notify();
19728        }
19729    }
19730
19731    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19732        self.set_show_scrollbars(false, cx);
19733        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
19734    }
19735
19736    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19737        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
19738    }
19739
19740    /// Normally the text in full mode and auto height editors is padded on the
19741    /// left side by roughly half a character width for improved hit testing.
19742    ///
19743    /// Use this method to disable this for cases where this is not wanted (e.g.
19744    /// if you want to align the editor text with some other text above or below)
19745    /// or if you want to add this padding to single-line editors.
19746    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
19747        self.offset_content = offset_content;
19748        cx.notify();
19749    }
19750
19751    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
19752        self.show_line_numbers = Some(show_line_numbers);
19753        cx.notify();
19754    }
19755
19756    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
19757        self.disable_expand_excerpt_buttons = true;
19758        cx.notify();
19759    }
19760
19761    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
19762        self.show_git_diff_gutter = Some(show_git_diff_gutter);
19763        cx.notify();
19764    }
19765
19766    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
19767        self.show_code_actions = Some(show_code_actions);
19768        cx.notify();
19769    }
19770
19771    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
19772        self.show_runnables = Some(show_runnables);
19773        cx.notify();
19774    }
19775
19776    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
19777        self.show_breakpoints = Some(show_breakpoints);
19778        cx.notify();
19779    }
19780
19781    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
19782        if self.display_map.read(cx).masked != masked {
19783            self.display_map.update(cx, |map, _| map.masked = masked);
19784        }
19785        cx.notify()
19786    }
19787
19788    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
19789        self.show_wrap_guides = Some(show_wrap_guides);
19790        cx.notify();
19791    }
19792
19793    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
19794        self.show_indent_guides = Some(show_indent_guides);
19795        cx.notify();
19796    }
19797
19798    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
19799        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
19800            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local())
19801                && let Some(dir) = file.abs_path(cx).parent()
19802            {
19803                return Some(dir.to_owned());
19804            }
19805        }
19806
19807        None
19808    }
19809
19810    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
19811        self.active_excerpt(cx)?
19812            .1
19813            .read(cx)
19814            .file()
19815            .and_then(|f| f.as_local())
19816    }
19817
19818    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
19819        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
19820            let buffer = buffer.read(cx);
19821            if let Some(project_path) = buffer.project_path(cx) {
19822                let project = self.project()?.read(cx);
19823                project.absolute_path(&project_path, cx)
19824            } else {
19825                buffer
19826                    .file()
19827                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
19828            }
19829        })
19830    }
19831
19832    pub fn reveal_in_finder(
19833        &mut self,
19834        _: &RevealInFileManager,
19835        _window: &mut Window,
19836        cx: &mut Context<Self>,
19837    ) {
19838        if let Some(target) = self.target_file(cx) {
19839            cx.reveal_path(&target.abs_path(cx));
19840        }
19841    }
19842
19843    pub fn copy_path(
19844        &mut self,
19845        _: &zed_actions::workspace::CopyPath,
19846        _window: &mut Window,
19847        cx: &mut Context<Self>,
19848    ) {
19849        if let Some(path) = self.target_file_abs_path(cx)
19850            && let Some(path) = path.to_str()
19851        {
19852            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
19853        } else {
19854            cx.propagate();
19855        }
19856    }
19857
19858    pub fn copy_relative_path(
19859        &mut self,
19860        _: &zed_actions::workspace::CopyRelativePath,
19861        _window: &mut Window,
19862        cx: &mut Context<Self>,
19863    ) {
19864        if let Some(path) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
19865            let project = self.project()?.read(cx);
19866            let path = buffer.read(cx).file()?.path();
19867            let path = path.display(project.path_style(cx));
19868            Some(path)
19869        }) {
19870            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
19871        } else {
19872            cx.propagate();
19873        }
19874    }
19875
19876    /// Returns the project path for the editor's buffer, if any buffer is
19877    /// opened in the editor.
19878    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
19879        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
19880            buffer.read(cx).project_path(cx)
19881        } else {
19882            None
19883        }
19884    }
19885
19886    // Returns true if the editor handled a go-to-line request
19887    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
19888        maybe!({
19889            let breakpoint_store = self.breakpoint_store.as_ref()?;
19890
19891            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
19892            else {
19893                self.clear_row_highlights::<ActiveDebugLine>();
19894                return None;
19895            };
19896
19897            let position = active_stack_frame.position;
19898            let buffer_id = position.buffer_id?;
19899            let snapshot = self
19900                .project
19901                .as_ref()?
19902                .read(cx)
19903                .buffer_for_id(buffer_id, cx)?
19904                .read(cx)
19905                .snapshot();
19906
19907            let mut handled = false;
19908            for (id, ExcerptRange { context, .. }) in
19909                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
19910            {
19911                if context.start.cmp(&position, &snapshot).is_ge()
19912                    || context.end.cmp(&position, &snapshot).is_lt()
19913                {
19914                    continue;
19915                }
19916                let snapshot = self.buffer.read(cx).snapshot(cx);
19917                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
19918
19919                handled = true;
19920                self.clear_row_highlights::<ActiveDebugLine>();
19921
19922                self.go_to_line::<ActiveDebugLine>(
19923                    multibuffer_anchor,
19924                    Some(cx.theme().colors().editor_debugger_active_line_background),
19925                    window,
19926                    cx,
19927                );
19928
19929                cx.notify();
19930            }
19931
19932            handled.then_some(())
19933        })
19934        .is_some()
19935    }
19936
19937    pub fn copy_file_name_without_extension(
19938        &mut self,
19939        _: &CopyFileNameWithoutExtension,
19940        _: &mut Window,
19941        cx: &mut Context<Self>,
19942    ) {
19943        if let Some(file) = self.target_file(cx)
19944            && let Some(file_stem) = file.path().file_stem()
19945        {
19946            cx.write_to_clipboard(ClipboardItem::new_string(file_stem.to_string()));
19947        }
19948    }
19949
19950    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
19951        if let Some(file) = self.target_file(cx)
19952            && let Some(name) = file.path().file_name()
19953        {
19954            cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
19955        }
19956    }
19957
19958    pub fn toggle_git_blame(
19959        &mut self,
19960        _: &::git::Blame,
19961        window: &mut Window,
19962        cx: &mut Context<Self>,
19963    ) {
19964        self.show_git_blame_gutter = !self.show_git_blame_gutter;
19965
19966        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
19967            self.start_git_blame(true, window, cx);
19968        }
19969
19970        cx.notify();
19971    }
19972
19973    pub fn toggle_git_blame_inline(
19974        &mut self,
19975        _: &ToggleGitBlameInline,
19976        window: &mut Window,
19977        cx: &mut Context<Self>,
19978    ) {
19979        self.toggle_git_blame_inline_internal(true, window, cx);
19980        cx.notify();
19981    }
19982
19983    pub fn open_git_blame_commit(
19984        &mut self,
19985        _: &OpenGitBlameCommit,
19986        window: &mut Window,
19987        cx: &mut Context<Self>,
19988    ) {
19989        self.open_git_blame_commit_internal(window, cx);
19990    }
19991
19992    fn open_git_blame_commit_internal(
19993        &mut self,
19994        window: &mut Window,
19995        cx: &mut Context<Self>,
19996    ) -> Option<()> {
19997        let blame = self.blame.as_ref()?;
19998        let snapshot = self.snapshot(window, cx);
19999        let cursor = self
20000            .selections
20001            .newest::<Point>(&snapshot.display_snapshot)
20002            .head();
20003        let (buffer, point, _) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)?;
20004        let (_, blame_entry) = blame
20005            .update(cx, |blame, cx| {
20006                blame
20007                    .blame_for_rows(
20008                        &[RowInfo {
20009                            buffer_id: Some(buffer.remote_id()),
20010                            buffer_row: Some(point.row),
20011                            ..Default::default()
20012                        }],
20013                        cx,
20014                    )
20015                    .next()
20016            })
20017            .flatten()?;
20018        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
20019        let repo = blame.read(cx).repository(cx, buffer.remote_id())?;
20020        let workspace = self.workspace()?.downgrade();
20021        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
20022        None
20023    }
20024
20025    pub fn git_blame_inline_enabled(&self) -> bool {
20026        self.git_blame_inline_enabled
20027    }
20028
20029    pub fn toggle_selection_menu(
20030        &mut self,
20031        _: &ToggleSelectionMenu,
20032        _: &mut Window,
20033        cx: &mut Context<Self>,
20034    ) {
20035        self.show_selection_menu = self
20036            .show_selection_menu
20037            .map(|show_selections_menu| !show_selections_menu)
20038            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
20039
20040        cx.notify();
20041    }
20042
20043    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
20044        self.show_selection_menu
20045            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
20046    }
20047
20048    fn start_git_blame(
20049        &mut self,
20050        user_triggered: bool,
20051        window: &mut Window,
20052        cx: &mut Context<Self>,
20053    ) {
20054        if let Some(project) = self.project() {
20055            if let Some(buffer) = self.buffer().read(cx).as_singleton()
20056                && buffer.read(cx).file().is_none()
20057            {
20058                return;
20059            }
20060
20061            let focused = self.focus_handle(cx).contains_focused(window, cx);
20062
20063            let project = project.clone();
20064            let blame = cx
20065                .new(|cx| GitBlame::new(self.buffer.clone(), project, user_triggered, focused, cx));
20066            self.blame_subscription =
20067                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
20068            self.blame = Some(blame);
20069        }
20070    }
20071
20072    fn toggle_git_blame_inline_internal(
20073        &mut self,
20074        user_triggered: bool,
20075        window: &mut Window,
20076        cx: &mut Context<Self>,
20077    ) {
20078        if self.git_blame_inline_enabled {
20079            self.git_blame_inline_enabled = false;
20080            self.show_git_blame_inline = false;
20081            self.show_git_blame_inline_delay_task.take();
20082        } else {
20083            self.git_blame_inline_enabled = true;
20084            self.start_git_blame_inline(user_triggered, window, cx);
20085        }
20086
20087        cx.notify();
20088    }
20089
20090    fn start_git_blame_inline(
20091        &mut self,
20092        user_triggered: bool,
20093        window: &mut Window,
20094        cx: &mut Context<Self>,
20095    ) {
20096        self.start_git_blame(user_triggered, window, cx);
20097
20098        if ProjectSettings::get_global(cx)
20099            .git
20100            .inline_blame_delay()
20101            .is_some()
20102        {
20103            self.start_inline_blame_timer(window, cx);
20104        } else {
20105            self.show_git_blame_inline = true
20106        }
20107    }
20108
20109    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
20110        self.blame.as_ref()
20111    }
20112
20113    pub fn show_git_blame_gutter(&self) -> bool {
20114        self.show_git_blame_gutter
20115    }
20116
20117    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
20118        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
20119    }
20120
20121    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
20122        self.show_git_blame_inline
20123            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
20124            && !self.newest_selection_head_on_empty_line(cx)
20125            && self.has_blame_entries(cx)
20126    }
20127
20128    fn has_blame_entries(&self, cx: &App) -> bool {
20129        self.blame()
20130            .is_some_and(|blame| blame.read(cx).has_generated_entries())
20131    }
20132
20133    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
20134        let cursor_anchor = self.selections.newest_anchor().head();
20135
20136        let snapshot = self.buffer.read(cx).snapshot(cx);
20137        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
20138
20139        snapshot.line_len(buffer_row) == 0
20140    }
20141
20142    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
20143        let buffer_and_selection = maybe!({
20144            let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
20145            let selection_range = selection.range();
20146
20147            let multi_buffer = self.buffer().read(cx);
20148            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
20149            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
20150
20151            let (buffer, range, _) = if selection.reversed {
20152                buffer_ranges.first()
20153            } else {
20154                buffer_ranges.last()
20155            }?;
20156
20157            let selection = text::ToPoint::to_point(&range.start, buffer).row
20158                ..text::ToPoint::to_point(&range.end, buffer).row;
20159            Some((multi_buffer.buffer(buffer.remote_id()).unwrap(), selection))
20160        });
20161
20162        let Some((buffer, selection)) = buffer_and_selection else {
20163            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
20164        };
20165
20166        let Some(project) = self.project() else {
20167            return Task::ready(Err(anyhow!("editor does not have project")));
20168        };
20169
20170        project.update(cx, |project, cx| {
20171            project.get_permalink_to_line(&buffer, selection, cx)
20172        })
20173    }
20174
20175    pub fn copy_permalink_to_line(
20176        &mut self,
20177        _: &CopyPermalinkToLine,
20178        window: &mut Window,
20179        cx: &mut Context<Self>,
20180    ) {
20181        let permalink_task = self.get_permalink_to_line(cx);
20182        let workspace = self.workspace();
20183
20184        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
20185            Ok(permalink) => {
20186                cx.update(|_, cx| {
20187                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
20188                })
20189                .ok();
20190            }
20191            Err(err) => {
20192                let message = format!("Failed to copy permalink: {err}");
20193
20194                anyhow::Result::<()>::Err(err).log_err();
20195
20196                if let Some(workspace) = workspace {
20197                    workspace
20198                        .update_in(cx, |workspace, _, cx| {
20199                            struct CopyPermalinkToLine;
20200
20201                            workspace.show_toast(
20202                                Toast::new(
20203                                    NotificationId::unique::<CopyPermalinkToLine>(),
20204                                    message,
20205                                ),
20206                                cx,
20207                            )
20208                        })
20209                        .ok();
20210                }
20211            }
20212        })
20213        .detach();
20214    }
20215
20216    pub fn copy_file_location(
20217        &mut self,
20218        _: &CopyFileLocation,
20219        _: &mut Window,
20220        cx: &mut Context<Self>,
20221    ) {
20222        let selection = self
20223            .selections
20224            .newest::<Point>(&self.display_snapshot(cx))
20225            .start
20226            .row
20227            + 1;
20228        if let Some(file) = self.target_file(cx) {
20229            let path = file.path().display(file.path_style(cx));
20230            cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
20231        }
20232    }
20233
20234    pub fn open_permalink_to_line(
20235        &mut self,
20236        _: &OpenPermalinkToLine,
20237        window: &mut Window,
20238        cx: &mut Context<Self>,
20239    ) {
20240        let permalink_task = self.get_permalink_to_line(cx);
20241        let workspace = self.workspace();
20242
20243        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
20244            Ok(permalink) => {
20245                cx.update(|_, cx| {
20246                    cx.open_url(permalink.as_ref());
20247                })
20248                .ok();
20249            }
20250            Err(err) => {
20251                let message = format!("Failed to open permalink: {err}");
20252
20253                anyhow::Result::<()>::Err(err).log_err();
20254
20255                if let Some(workspace) = workspace {
20256                    workspace
20257                        .update(cx, |workspace, cx| {
20258                            struct OpenPermalinkToLine;
20259
20260                            workspace.show_toast(
20261                                Toast::new(
20262                                    NotificationId::unique::<OpenPermalinkToLine>(),
20263                                    message,
20264                                ),
20265                                cx,
20266                            )
20267                        })
20268                        .ok();
20269                }
20270            }
20271        })
20272        .detach();
20273    }
20274
20275    pub fn insert_uuid_v4(
20276        &mut self,
20277        _: &InsertUuidV4,
20278        window: &mut Window,
20279        cx: &mut Context<Self>,
20280    ) {
20281        self.insert_uuid(UuidVersion::V4, window, cx);
20282    }
20283
20284    pub fn insert_uuid_v7(
20285        &mut self,
20286        _: &InsertUuidV7,
20287        window: &mut Window,
20288        cx: &mut Context<Self>,
20289    ) {
20290        self.insert_uuid(UuidVersion::V7, window, cx);
20291    }
20292
20293    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
20294        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
20295        self.transact(window, cx, |this, window, cx| {
20296            let edits = this
20297                .selections
20298                .all::<Point>(&this.display_snapshot(cx))
20299                .into_iter()
20300                .map(|selection| {
20301                    let uuid = match version {
20302                        UuidVersion::V4 => uuid::Uuid::new_v4(),
20303                        UuidVersion::V7 => uuid::Uuid::now_v7(),
20304                    };
20305
20306                    (selection.range(), uuid.to_string())
20307                });
20308            this.edit(edits, cx);
20309            this.refresh_edit_prediction(true, false, window, cx);
20310        });
20311    }
20312
20313    pub fn open_selections_in_multibuffer(
20314        &mut self,
20315        _: &OpenSelectionsInMultibuffer,
20316        window: &mut Window,
20317        cx: &mut Context<Self>,
20318    ) {
20319        let multibuffer = self.buffer.read(cx);
20320
20321        let Some(buffer) = multibuffer.as_singleton() else {
20322            return;
20323        };
20324
20325        let Some(workspace) = self.workspace() else {
20326            return;
20327        };
20328
20329        let title = multibuffer.title(cx).to_string();
20330
20331        let locations = self
20332            .selections
20333            .all_anchors(&self.display_snapshot(cx))
20334            .iter()
20335            .map(|selection| {
20336                (
20337                    buffer.clone(),
20338                    (selection.start.text_anchor..selection.end.text_anchor)
20339                        .to_point(buffer.read(cx)),
20340                )
20341            })
20342            .into_group_map();
20343
20344        cx.spawn_in(window, async move |_, cx| {
20345            workspace.update_in(cx, |workspace, window, cx| {
20346                Self::open_locations_in_multibuffer(
20347                    workspace,
20348                    locations,
20349                    format!("Selections for '{title}'"),
20350                    false,
20351                    MultibufferSelectionMode::All,
20352                    window,
20353                    cx,
20354                );
20355            })
20356        })
20357        .detach();
20358    }
20359
20360    /// Adds a row highlight for the given range. If a row has multiple highlights, the
20361    /// last highlight added will be used.
20362    ///
20363    /// If the range ends at the beginning of a line, then that line will not be highlighted.
20364    pub fn highlight_rows<T: 'static>(
20365        &mut self,
20366        range: Range<Anchor>,
20367        color: Hsla,
20368        options: RowHighlightOptions,
20369        cx: &mut Context<Self>,
20370    ) {
20371        let snapshot = self.buffer().read(cx).snapshot(cx);
20372        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
20373        let ix = row_highlights.binary_search_by(|highlight| {
20374            Ordering::Equal
20375                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
20376                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
20377        });
20378
20379        if let Err(mut ix) = ix {
20380            let index = post_inc(&mut self.highlight_order);
20381
20382            // If this range intersects with the preceding highlight, then merge it with
20383            // the preceding highlight. Otherwise insert a new highlight.
20384            let mut merged = false;
20385            if ix > 0 {
20386                let prev_highlight = &mut row_highlights[ix - 1];
20387                if prev_highlight
20388                    .range
20389                    .end
20390                    .cmp(&range.start, &snapshot)
20391                    .is_ge()
20392                {
20393                    ix -= 1;
20394                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
20395                        prev_highlight.range.end = range.end;
20396                    }
20397                    merged = true;
20398                    prev_highlight.index = index;
20399                    prev_highlight.color = color;
20400                    prev_highlight.options = options;
20401                }
20402            }
20403
20404            if !merged {
20405                row_highlights.insert(
20406                    ix,
20407                    RowHighlight {
20408                        range,
20409                        index,
20410                        color,
20411                        options,
20412                        type_id: TypeId::of::<T>(),
20413                    },
20414                );
20415            }
20416
20417            // If any of the following highlights intersect with this one, merge them.
20418            while let Some(next_highlight) = row_highlights.get(ix + 1) {
20419                let highlight = &row_highlights[ix];
20420                if next_highlight
20421                    .range
20422                    .start
20423                    .cmp(&highlight.range.end, &snapshot)
20424                    .is_le()
20425                {
20426                    if next_highlight
20427                        .range
20428                        .end
20429                        .cmp(&highlight.range.end, &snapshot)
20430                        .is_gt()
20431                    {
20432                        row_highlights[ix].range.end = next_highlight.range.end;
20433                    }
20434                    row_highlights.remove(ix + 1);
20435                } else {
20436                    break;
20437                }
20438            }
20439        }
20440    }
20441
20442    /// Remove any highlighted row ranges of the given type that intersect the
20443    /// given ranges.
20444    pub fn remove_highlighted_rows<T: 'static>(
20445        &mut self,
20446        ranges_to_remove: Vec<Range<Anchor>>,
20447        cx: &mut Context<Self>,
20448    ) {
20449        let snapshot = self.buffer().read(cx).snapshot(cx);
20450        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
20451        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
20452        row_highlights.retain(|highlight| {
20453            while let Some(range_to_remove) = ranges_to_remove.peek() {
20454                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
20455                    Ordering::Less | Ordering::Equal => {
20456                        ranges_to_remove.next();
20457                    }
20458                    Ordering::Greater => {
20459                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
20460                            Ordering::Less | Ordering::Equal => {
20461                                return false;
20462                            }
20463                            Ordering::Greater => break,
20464                        }
20465                    }
20466                }
20467            }
20468
20469            true
20470        })
20471    }
20472
20473    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
20474    pub fn clear_row_highlights<T: 'static>(&mut self) {
20475        self.highlighted_rows.remove(&TypeId::of::<T>());
20476    }
20477
20478    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
20479    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
20480        self.highlighted_rows
20481            .get(&TypeId::of::<T>())
20482            .map_or(&[] as &[_], |vec| vec.as_slice())
20483            .iter()
20484            .map(|highlight| (highlight.range.clone(), highlight.color))
20485    }
20486
20487    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
20488    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
20489    /// Allows to ignore certain kinds of highlights.
20490    pub fn highlighted_display_rows(
20491        &self,
20492        window: &mut Window,
20493        cx: &mut App,
20494    ) -> BTreeMap<DisplayRow, LineHighlight> {
20495        let snapshot = self.snapshot(window, cx);
20496        let mut used_highlight_orders = HashMap::default();
20497        self.highlighted_rows
20498            .iter()
20499            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
20500            .fold(
20501                BTreeMap::<DisplayRow, LineHighlight>::new(),
20502                |mut unique_rows, highlight| {
20503                    let start = highlight.range.start.to_display_point(&snapshot);
20504                    let end = highlight.range.end.to_display_point(&snapshot);
20505                    let start_row = start.row().0;
20506                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
20507                        && end.column() == 0
20508                    {
20509                        end.row().0.saturating_sub(1)
20510                    } else {
20511                        end.row().0
20512                    };
20513                    for row in start_row..=end_row {
20514                        let used_index =
20515                            used_highlight_orders.entry(row).or_insert(highlight.index);
20516                        if highlight.index >= *used_index {
20517                            *used_index = highlight.index;
20518                            unique_rows.insert(
20519                                DisplayRow(row),
20520                                LineHighlight {
20521                                    include_gutter: highlight.options.include_gutter,
20522                                    border: None,
20523                                    background: highlight.color.into(),
20524                                    type_id: Some(highlight.type_id),
20525                                },
20526                            );
20527                        }
20528                    }
20529                    unique_rows
20530                },
20531            )
20532    }
20533
20534    pub fn highlighted_display_row_for_autoscroll(
20535        &self,
20536        snapshot: &DisplaySnapshot,
20537    ) -> Option<DisplayRow> {
20538        self.highlighted_rows
20539            .values()
20540            .flat_map(|highlighted_rows| highlighted_rows.iter())
20541            .filter_map(|highlight| {
20542                if highlight.options.autoscroll {
20543                    Some(highlight.range.start.to_display_point(snapshot).row())
20544                } else {
20545                    None
20546                }
20547            })
20548            .min()
20549    }
20550
20551    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
20552        self.highlight_background::<SearchWithinRange>(
20553            ranges,
20554            |colors| colors.colors().editor_document_highlight_read_background,
20555            cx,
20556        )
20557    }
20558
20559    pub fn set_breadcrumb_header(&mut self, new_header: String) {
20560        self.breadcrumb_header = Some(new_header);
20561    }
20562
20563    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
20564        self.clear_background_highlights::<SearchWithinRange>(cx);
20565    }
20566
20567    pub fn highlight_background<T: 'static>(
20568        &mut self,
20569        ranges: &[Range<Anchor>],
20570        color_fetcher: fn(&Theme) -> Hsla,
20571        cx: &mut Context<Self>,
20572    ) {
20573        self.background_highlights.insert(
20574            HighlightKey::Type(TypeId::of::<T>()),
20575            (color_fetcher, Arc::from(ranges)),
20576        );
20577        self.scrollbar_marker_state.dirty = true;
20578        cx.notify();
20579    }
20580
20581    pub fn highlight_background_key<T: 'static>(
20582        &mut self,
20583        key: usize,
20584        ranges: &[Range<Anchor>],
20585        color_fetcher: fn(&Theme) -> Hsla,
20586        cx: &mut Context<Self>,
20587    ) {
20588        self.background_highlights.insert(
20589            HighlightKey::TypePlus(TypeId::of::<T>(), key),
20590            (color_fetcher, Arc::from(ranges)),
20591        );
20592        self.scrollbar_marker_state.dirty = true;
20593        cx.notify();
20594    }
20595
20596    pub fn clear_background_highlights<T: 'static>(
20597        &mut self,
20598        cx: &mut Context<Self>,
20599    ) -> Option<BackgroundHighlight> {
20600        let text_highlights = self
20601            .background_highlights
20602            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
20603        if !text_highlights.1.is_empty() {
20604            self.scrollbar_marker_state.dirty = true;
20605            cx.notify();
20606        }
20607        Some(text_highlights)
20608    }
20609
20610    pub fn highlight_gutter<T: 'static>(
20611        &mut self,
20612        ranges: impl Into<Vec<Range<Anchor>>>,
20613        color_fetcher: fn(&App) -> Hsla,
20614        cx: &mut Context<Self>,
20615    ) {
20616        self.gutter_highlights
20617            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
20618        cx.notify();
20619    }
20620
20621    pub fn clear_gutter_highlights<T: 'static>(
20622        &mut self,
20623        cx: &mut Context<Self>,
20624    ) -> Option<GutterHighlight> {
20625        cx.notify();
20626        self.gutter_highlights.remove(&TypeId::of::<T>())
20627    }
20628
20629    pub fn insert_gutter_highlight<T: 'static>(
20630        &mut self,
20631        range: Range<Anchor>,
20632        color_fetcher: fn(&App) -> Hsla,
20633        cx: &mut Context<Self>,
20634    ) {
20635        let snapshot = self.buffer().read(cx).snapshot(cx);
20636        let mut highlights = self
20637            .gutter_highlights
20638            .remove(&TypeId::of::<T>())
20639            .map(|(_, highlights)| highlights)
20640            .unwrap_or_default();
20641        let ix = highlights.binary_search_by(|highlight| {
20642            Ordering::Equal
20643                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
20644                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
20645        });
20646        if let Err(ix) = ix {
20647            highlights.insert(ix, range);
20648        }
20649        self.gutter_highlights
20650            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
20651    }
20652
20653    pub fn remove_gutter_highlights<T: 'static>(
20654        &mut self,
20655        ranges_to_remove: Vec<Range<Anchor>>,
20656        cx: &mut Context<Self>,
20657    ) {
20658        let snapshot = self.buffer().read(cx).snapshot(cx);
20659        let Some((color_fetcher, mut gutter_highlights)) =
20660            self.gutter_highlights.remove(&TypeId::of::<T>())
20661        else {
20662            return;
20663        };
20664        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
20665        gutter_highlights.retain(|highlight| {
20666            while let Some(range_to_remove) = ranges_to_remove.peek() {
20667                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
20668                    Ordering::Less | Ordering::Equal => {
20669                        ranges_to_remove.next();
20670                    }
20671                    Ordering::Greater => {
20672                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
20673                            Ordering::Less | Ordering::Equal => {
20674                                return false;
20675                            }
20676                            Ordering::Greater => break,
20677                        }
20678                    }
20679                }
20680            }
20681
20682            true
20683        });
20684        self.gutter_highlights
20685            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
20686    }
20687
20688    #[cfg(feature = "test-support")]
20689    pub fn all_text_highlights(
20690        &self,
20691        window: &mut Window,
20692        cx: &mut Context<Self>,
20693    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
20694        let snapshot = self.snapshot(window, cx);
20695        self.display_map.update(cx, |display_map, _| {
20696            display_map
20697                .all_text_highlights()
20698                .map(|highlight| {
20699                    let (style, ranges) = highlight.as_ref();
20700                    (
20701                        *style,
20702                        ranges
20703                            .iter()
20704                            .map(|range| range.clone().to_display_points(&snapshot))
20705                            .collect(),
20706                    )
20707                })
20708                .collect()
20709        })
20710    }
20711
20712    #[cfg(feature = "test-support")]
20713    pub fn all_text_background_highlights(
20714        &self,
20715        window: &mut Window,
20716        cx: &mut Context<Self>,
20717    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20718        let snapshot = self.snapshot(window, cx);
20719        let buffer = &snapshot.buffer_snapshot();
20720        let start = buffer.anchor_before(0);
20721        let end = buffer.anchor_after(buffer.len());
20722        self.sorted_background_highlights_in_range(start..end, &snapshot, cx.theme())
20723    }
20724
20725    #[cfg(any(test, feature = "test-support"))]
20726    pub fn sorted_background_highlights_in_range(
20727        &self,
20728        search_range: Range<Anchor>,
20729        display_snapshot: &DisplaySnapshot,
20730        theme: &Theme,
20731    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20732        let mut res = self.background_highlights_in_range(search_range, display_snapshot, theme);
20733        res.sort_by(|a, b| {
20734            a.0.start
20735                .cmp(&b.0.start)
20736                .then_with(|| a.0.end.cmp(&b.0.end))
20737                .then_with(|| a.1.cmp(&b.1))
20738        });
20739        res
20740    }
20741
20742    #[cfg(feature = "test-support")]
20743    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
20744        let snapshot = self.buffer().read(cx).snapshot(cx);
20745
20746        let highlights = self
20747            .background_highlights
20748            .get(&HighlightKey::Type(TypeId::of::<
20749                items::BufferSearchHighlights,
20750            >()));
20751
20752        if let Some((_color, ranges)) = highlights {
20753            ranges
20754                .iter()
20755                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
20756                .collect_vec()
20757        } else {
20758            vec![]
20759        }
20760    }
20761
20762    fn document_highlights_for_position<'a>(
20763        &'a self,
20764        position: Anchor,
20765        buffer: &'a MultiBufferSnapshot,
20766    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
20767        let read_highlights = self
20768            .background_highlights
20769            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
20770            .map(|h| &h.1);
20771        let write_highlights = self
20772            .background_highlights
20773            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
20774            .map(|h| &h.1);
20775        let left_position = position.bias_left(buffer);
20776        let right_position = position.bias_right(buffer);
20777        read_highlights
20778            .into_iter()
20779            .chain(write_highlights)
20780            .flat_map(move |ranges| {
20781                let start_ix = match ranges.binary_search_by(|probe| {
20782                    let cmp = probe.end.cmp(&left_position, buffer);
20783                    if cmp.is_ge() {
20784                        Ordering::Greater
20785                    } else {
20786                        Ordering::Less
20787                    }
20788                }) {
20789                    Ok(i) | Err(i) => i,
20790                };
20791
20792                ranges[start_ix..]
20793                    .iter()
20794                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
20795            })
20796    }
20797
20798    pub fn has_background_highlights<T: 'static>(&self) -> bool {
20799        self.background_highlights
20800            .get(&HighlightKey::Type(TypeId::of::<T>()))
20801            .is_some_and(|(_, highlights)| !highlights.is_empty())
20802    }
20803
20804    /// Returns all background highlights for a given range.
20805    ///
20806    /// The order of highlights is not deterministic, do sort the ranges if needed for the logic.
20807    pub fn background_highlights_in_range(
20808        &self,
20809        search_range: Range<Anchor>,
20810        display_snapshot: &DisplaySnapshot,
20811        theme: &Theme,
20812    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20813        let mut results = Vec::new();
20814        for (color_fetcher, ranges) in self.background_highlights.values() {
20815            let color = color_fetcher(theme);
20816            let start_ix = match ranges.binary_search_by(|probe| {
20817                let cmp = probe
20818                    .end
20819                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
20820                if cmp.is_gt() {
20821                    Ordering::Greater
20822                } else {
20823                    Ordering::Less
20824                }
20825            }) {
20826                Ok(i) | Err(i) => i,
20827            };
20828            for range in &ranges[start_ix..] {
20829                if range
20830                    .start
20831                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
20832                    .is_ge()
20833                {
20834                    break;
20835                }
20836
20837                let start = range.start.to_display_point(display_snapshot);
20838                let end = range.end.to_display_point(display_snapshot);
20839                results.push((start..end, color))
20840            }
20841        }
20842        results
20843    }
20844
20845    pub fn gutter_highlights_in_range(
20846        &self,
20847        search_range: Range<Anchor>,
20848        display_snapshot: &DisplaySnapshot,
20849        cx: &App,
20850    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20851        let mut results = Vec::new();
20852        for (color_fetcher, ranges) in self.gutter_highlights.values() {
20853            let color = color_fetcher(cx);
20854            let start_ix = match ranges.binary_search_by(|probe| {
20855                let cmp = probe
20856                    .end
20857                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
20858                if cmp.is_gt() {
20859                    Ordering::Greater
20860                } else {
20861                    Ordering::Less
20862                }
20863            }) {
20864                Ok(i) | Err(i) => i,
20865            };
20866            for range in &ranges[start_ix..] {
20867                if range
20868                    .start
20869                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
20870                    .is_ge()
20871                {
20872                    break;
20873                }
20874
20875                let start = range.start.to_display_point(display_snapshot);
20876                let end = range.end.to_display_point(display_snapshot);
20877                results.push((start..end, color))
20878            }
20879        }
20880        results
20881    }
20882
20883    /// Get the text ranges corresponding to the redaction query
20884    pub fn redacted_ranges(
20885        &self,
20886        search_range: Range<Anchor>,
20887        display_snapshot: &DisplaySnapshot,
20888        cx: &App,
20889    ) -> Vec<Range<DisplayPoint>> {
20890        display_snapshot
20891            .buffer_snapshot()
20892            .redacted_ranges(search_range, |file| {
20893                if let Some(file) = file {
20894                    file.is_private()
20895                        && EditorSettings::get(
20896                            Some(SettingsLocation {
20897                                worktree_id: file.worktree_id(cx),
20898                                path: file.path().as_ref(),
20899                            }),
20900                            cx,
20901                        )
20902                        .redact_private_values
20903                } else {
20904                    false
20905                }
20906            })
20907            .map(|range| {
20908                range.start.to_display_point(display_snapshot)
20909                    ..range.end.to_display_point(display_snapshot)
20910            })
20911            .collect()
20912    }
20913
20914    pub fn highlight_text_key<T: 'static>(
20915        &mut self,
20916        key: usize,
20917        ranges: Vec<Range<Anchor>>,
20918        style: HighlightStyle,
20919        cx: &mut Context<Self>,
20920    ) {
20921        self.display_map.update(cx, |map, _| {
20922            map.highlight_text(
20923                HighlightKey::TypePlus(TypeId::of::<T>(), key),
20924                ranges,
20925                style,
20926            );
20927        });
20928        cx.notify();
20929    }
20930
20931    pub fn highlight_text<T: 'static>(
20932        &mut self,
20933        ranges: Vec<Range<Anchor>>,
20934        style: HighlightStyle,
20935        cx: &mut Context<Self>,
20936    ) {
20937        self.display_map.update(cx, |map, _| {
20938            map.highlight_text(HighlightKey::Type(TypeId::of::<T>()), ranges, style, false)
20939        });
20940        cx.notify();
20941    }
20942
20943    pub fn text_highlights<'a, T: 'static>(
20944        &'a self,
20945        cx: &'a App,
20946    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
20947        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
20948    }
20949
20950    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
20951        let cleared = self
20952            .display_map
20953            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
20954        if cleared {
20955            cx.notify();
20956        }
20957    }
20958
20959    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
20960        (self.read_only(cx) || self.blink_manager.read(cx).visible())
20961            && self.focus_handle.is_focused(window)
20962    }
20963
20964    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
20965        self.show_cursor_when_unfocused = is_enabled;
20966        cx.notify();
20967    }
20968
20969    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
20970        cx.notify();
20971    }
20972
20973    fn on_debug_session_event(
20974        &mut self,
20975        _session: Entity<Session>,
20976        event: &SessionEvent,
20977        cx: &mut Context<Self>,
20978    ) {
20979        if let SessionEvent::InvalidateInlineValue = event {
20980            self.refresh_inline_values(cx);
20981        }
20982    }
20983
20984    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
20985        let Some(project) = self.project.clone() else {
20986            return;
20987        };
20988
20989        if !self.inline_value_cache.enabled {
20990            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
20991            self.splice_inlays(&inlays, Vec::new(), cx);
20992            return;
20993        }
20994
20995        let current_execution_position = self
20996            .highlighted_rows
20997            .get(&TypeId::of::<ActiveDebugLine>())
20998            .and_then(|lines| lines.last().map(|line| line.range.end));
20999
21000        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
21001            let inline_values = editor
21002                .update(cx, |editor, cx| {
21003                    let Some(current_execution_position) = current_execution_position else {
21004                        return Some(Task::ready(Ok(Vec::new())));
21005                    };
21006
21007                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
21008                        let snapshot = buffer.snapshot(cx);
21009
21010                        let excerpt = snapshot.excerpt_containing(
21011                            current_execution_position..current_execution_position,
21012                        )?;
21013
21014                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
21015                    })?;
21016
21017                    let range =
21018                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
21019
21020                    project.inline_values(buffer, range, cx)
21021                })
21022                .ok()
21023                .flatten()?
21024                .await
21025                .context("refreshing debugger inlays")
21026                .log_err()?;
21027
21028            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
21029
21030            for (buffer_id, inline_value) in inline_values
21031                .into_iter()
21032                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
21033            {
21034                buffer_inline_values
21035                    .entry(buffer_id)
21036                    .or_default()
21037                    .push(inline_value);
21038            }
21039
21040            editor
21041                .update(cx, |editor, cx| {
21042                    let snapshot = editor.buffer.read(cx).snapshot(cx);
21043                    let mut new_inlays = Vec::default();
21044
21045                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
21046                        let buffer_id = buffer_snapshot.remote_id();
21047                        buffer_inline_values
21048                            .get(&buffer_id)
21049                            .into_iter()
21050                            .flatten()
21051                            .for_each(|hint| {
21052                                let inlay = Inlay::debugger(
21053                                    post_inc(&mut editor.next_inlay_id),
21054                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
21055                                    hint.text(),
21056                                );
21057                                if !inlay.text().chars().contains(&'\n') {
21058                                    new_inlays.push(inlay);
21059                                }
21060                            });
21061                    }
21062
21063                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
21064                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
21065
21066                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
21067                })
21068                .ok()?;
21069            Some(())
21070        });
21071    }
21072
21073    fn on_buffer_event(
21074        &mut self,
21075        multibuffer: &Entity<MultiBuffer>,
21076        event: &multi_buffer::Event,
21077        window: &mut Window,
21078        cx: &mut Context<Self>,
21079    ) {
21080        match event {
21081            multi_buffer::Event::Edited { edited_buffer } => {
21082                self.scrollbar_marker_state.dirty = true;
21083                self.active_indent_guides_state.dirty = true;
21084                self.refresh_active_diagnostics(cx);
21085                self.refresh_code_actions(window, cx);
21086                self.refresh_selected_text_highlights(true, window, cx);
21087                self.refresh_single_line_folds(window, cx);
21088                self.colorize_brackets(true, cx);
21089                self.refresh_matching_bracket_highlights(window, cx);
21090                if self.has_active_edit_prediction() {
21091                    self.update_visible_edit_prediction(window, cx);
21092                }
21093
21094                if let Some(buffer) = edited_buffer {
21095                    if buffer.read(cx).file().is_none() {
21096                        cx.emit(EditorEvent::TitleChanged);
21097                    }
21098
21099                    if self.project.is_some() {
21100                        let buffer_id = buffer.read(cx).remote_id();
21101                        self.register_buffer(buffer_id, cx);
21102                        self.update_lsp_data(Some(buffer_id), window, cx);
21103                        self.refresh_inlay_hints(
21104                            InlayHintRefreshReason::BufferEdited(buffer_id),
21105                            cx,
21106                        );
21107                    }
21108                }
21109
21110                cx.emit(EditorEvent::BufferEdited);
21111                cx.emit(SearchEvent::MatchesInvalidated);
21112
21113                let Some(project) = &self.project else { return };
21114                let (telemetry, is_via_ssh) = {
21115                    let project = project.read(cx);
21116                    let telemetry = project.client().telemetry().clone();
21117                    let is_via_ssh = project.is_via_remote_server();
21118                    (telemetry, is_via_ssh)
21119                };
21120                telemetry.log_edit_event("editor", is_via_ssh);
21121            }
21122            multi_buffer::Event::ExcerptsAdded {
21123                buffer,
21124                predecessor,
21125                excerpts,
21126            } => {
21127                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21128                let buffer_id = buffer.read(cx).remote_id();
21129                if self.buffer.read(cx).diff_for(buffer_id).is_none()
21130                    && let Some(project) = &self.project
21131                {
21132                    update_uncommitted_diff_for_buffer(
21133                        cx.entity(),
21134                        project,
21135                        [buffer.clone()],
21136                        self.buffer.clone(),
21137                        cx,
21138                    )
21139                    .detach();
21140                }
21141                self.update_lsp_data(Some(buffer_id), window, cx);
21142                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
21143                self.colorize_brackets(false, cx);
21144                cx.emit(EditorEvent::ExcerptsAdded {
21145                    buffer: buffer.clone(),
21146                    predecessor: *predecessor,
21147                    excerpts: excerpts.clone(),
21148                });
21149            }
21150            multi_buffer::Event::ExcerptsRemoved {
21151                ids,
21152                removed_buffer_ids,
21153            } => {
21154                if let Some(inlay_hints) = &mut self.inlay_hints {
21155                    inlay_hints.remove_inlay_chunk_data(removed_buffer_ids);
21156                }
21157                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
21158                for buffer_id in removed_buffer_ids {
21159                    self.registered_buffers.remove(buffer_id);
21160                }
21161                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
21162                cx.emit(EditorEvent::ExcerptsRemoved {
21163                    ids: ids.clone(),
21164                    removed_buffer_ids: removed_buffer_ids.clone(),
21165                });
21166            }
21167            multi_buffer::Event::ExcerptsEdited {
21168                excerpt_ids,
21169                buffer_ids,
21170            } => {
21171                self.display_map.update(cx, |map, cx| {
21172                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
21173                });
21174                cx.emit(EditorEvent::ExcerptsEdited {
21175                    ids: excerpt_ids.clone(),
21176                });
21177            }
21178            multi_buffer::Event::ExcerptsExpanded { ids } => {
21179                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
21180                self.refresh_document_highlights(cx);
21181                for id in ids {
21182                    self.fetched_tree_sitter_chunks.remove(id);
21183                }
21184                self.colorize_brackets(false, cx);
21185                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
21186            }
21187            multi_buffer::Event::Reparsed(buffer_id) => {
21188                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21189                self.colorize_brackets(true, cx);
21190                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
21191
21192                cx.emit(EditorEvent::Reparsed(*buffer_id));
21193            }
21194            multi_buffer::Event::DiffHunksToggled => {
21195                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21196            }
21197            multi_buffer::Event::LanguageChanged(buffer_id) => {
21198                self.registered_buffers.remove(&buffer_id);
21199                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
21200                cx.emit(EditorEvent::Reparsed(*buffer_id));
21201                cx.notify();
21202            }
21203            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
21204            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
21205            multi_buffer::Event::FileHandleChanged
21206            | multi_buffer::Event::Reloaded
21207            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
21208            multi_buffer::Event::DiagnosticsUpdated => {
21209                self.update_diagnostics_state(window, cx);
21210            }
21211            _ => {}
21212        };
21213    }
21214
21215    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
21216        if !self.diagnostics_enabled() {
21217            return;
21218        }
21219        self.refresh_active_diagnostics(cx);
21220        self.refresh_inline_diagnostics(true, window, cx);
21221        self.scrollbar_marker_state.dirty = true;
21222        cx.notify();
21223    }
21224
21225    pub fn start_temporary_diff_override(&mut self) {
21226        self.load_diff_task.take();
21227        self.temporary_diff_override = true;
21228    }
21229
21230    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
21231        self.temporary_diff_override = false;
21232        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
21233        self.buffer.update(cx, |buffer, cx| {
21234            buffer.set_all_diff_hunks_collapsed(cx);
21235        });
21236
21237        if let Some(project) = self.project.clone() {
21238            self.load_diff_task = Some(
21239                update_uncommitted_diff_for_buffer(
21240                    cx.entity(),
21241                    &project,
21242                    self.buffer.read(cx).all_buffers(),
21243                    self.buffer.clone(),
21244                    cx,
21245                )
21246                .shared(),
21247            );
21248        }
21249    }
21250
21251    fn on_display_map_changed(
21252        &mut self,
21253        _: Entity<DisplayMap>,
21254        _: &mut Window,
21255        cx: &mut Context<Self>,
21256    ) {
21257        cx.notify();
21258    }
21259
21260    fn fetch_applicable_language_settings(
21261        &self,
21262        cx: &App,
21263    ) -> HashMap<Option<LanguageName>, LanguageSettings> {
21264        if !self.mode.is_full() {
21265            return HashMap::default();
21266        }
21267
21268        self.buffer().read(cx).all_buffers().into_iter().fold(
21269            HashMap::default(),
21270            |mut acc, buffer| {
21271                let buffer = buffer.read(cx);
21272                let language = buffer.language().map(|language| language.name());
21273                if let hash_map::Entry::Vacant(v) = acc.entry(language.clone()) {
21274                    let file = buffer.file();
21275                    v.insert(language_settings(language, file, cx).into_owned());
21276                }
21277                acc
21278            },
21279        )
21280    }
21281
21282    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21283        let new_language_settings = self.fetch_applicable_language_settings(cx);
21284        let language_settings_changed = new_language_settings != self.applicable_language_settings;
21285        if language_settings_changed {
21286            self.applicable_language_settings = new_language_settings;
21287        }
21288
21289        if self.diagnostics_enabled() {
21290            let new_severity = EditorSettings::get_global(cx)
21291                .diagnostics_max_severity
21292                .unwrap_or(DiagnosticSeverity::Hint);
21293            self.set_max_diagnostics_severity(new_severity, cx);
21294        }
21295        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21296        self.update_edit_prediction_settings(cx);
21297        self.refresh_edit_prediction(true, false, window, cx);
21298        self.refresh_inline_values(cx);
21299        self.refresh_inlay_hints(
21300            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
21301                self.selections.newest_anchor().head(),
21302                &self.buffer.read(cx).snapshot(cx),
21303                cx,
21304            )),
21305            cx,
21306        );
21307
21308        let old_cursor_shape = self.cursor_shape;
21309        let old_show_breadcrumbs = self.show_breadcrumbs;
21310
21311        {
21312            let editor_settings = EditorSettings::get_global(cx);
21313            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
21314            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
21315            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
21316            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
21317        }
21318
21319        if old_cursor_shape != self.cursor_shape {
21320            cx.emit(EditorEvent::CursorShapeChanged);
21321        }
21322
21323        if old_show_breadcrumbs != self.show_breadcrumbs {
21324            cx.emit(EditorEvent::BreadcrumbsChanged);
21325        }
21326
21327        let project_settings = ProjectSettings::get_global(cx);
21328        self.buffer_serialization = self
21329            .should_serialize_buffer()
21330            .then(|| BufferSerialization::new(project_settings.session.restore_unsaved_buffers));
21331
21332        if self.mode.is_full() {
21333            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
21334            let inline_blame_enabled = project_settings.git.inline_blame.enabled;
21335            if self.show_inline_diagnostics != show_inline_diagnostics {
21336                self.show_inline_diagnostics = show_inline_diagnostics;
21337                self.refresh_inline_diagnostics(false, window, cx);
21338            }
21339
21340            if self.git_blame_inline_enabled != inline_blame_enabled {
21341                self.toggle_git_blame_inline_internal(false, window, cx);
21342            }
21343
21344            let minimap_settings = EditorSettings::get_global(cx).minimap;
21345            if self.minimap_visibility != MinimapVisibility::Disabled {
21346                if self.minimap_visibility.settings_visibility()
21347                    != minimap_settings.minimap_enabled()
21348                {
21349                    self.set_minimap_visibility(
21350                        MinimapVisibility::for_mode(self.mode(), cx),
21351                        window,
21352                        cx,
21353                    );
21354                } else if let Some(minimap_entity) = self.minimap.as_ref() {
21355                    minimap_entity.update(cx, |minimap_editor, cx| {
21356                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
21357                    })
21358                }
21359            }
21360
21361            if language_settings_changed {
21362                self.colorize_brackets(true, cx);
21363            }
21364
21365            if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
21366                colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
21367            }) {
21368                if !inlay_splice.is_empty() {
21369                    self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
21370                }
21371                self.refresh_colors_for_visible_range(None, window, cx);
21372            }
21373        }
21374
21375        cx.notify();
21376    }
21377
21378    pub fn set_searchable(&mut self, searchable: bool) {
21379        self.searchable = searchable;
21380    }
21381
21382    pub fn searchable(&self) -> bool {
21383        self.searchable
21384    }
21385
21386    pub fn open_excerpts_in_split(
21387        &mut self,
21388        _: &OpenExcerptsSplit,
21389        window: &mut Window,
21390        cx: &mut Context<Self>,
21391    ) {
21392        self.open_excerpts_common(None, true, window, cx)
21393    }
21394
21395    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
21396        self.open_excerpts_common(None, false, window, cx)
21397    }
21398
21399    fn open_excerpts_common(
21400        &mut self,
21401        jump_data: Option<JumpData>,
21402        split: bool,
21403        window: &mut Window,
21404        cx: &mut Context<Self>,
21405    ) {
21406        let Some(workspace) = self.workspace() else {
21407            cx.propagate();
21408            return;
21409        };
21410
21411        if self.buffer.read(cx).is_singleton() {
21412            cx.propagate();
21413            return;
21414        }
21415
21416        let mut new_selections_by_buffer = HashMap::default();
21417        match &jump_data {
21418            Some(JumpData::MultiBufferPoint {
21419                excerpt_id,
21420                position,
21421                anchor,
21422                line_offset_from_top,
21423            }) => {
21424                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
21425                if let Some(buffer) = multi_buffer_snapshot
21426                    .buffer_id_for_excerpt(*excerpt_id)
21427                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
21428                {
21429                    let buffer_snapshot = buffer.read(cx).snapshot();
21430                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
21431                        language::ToPoint::to_point(anchor, &buffer_snapshot)
21432                    } else {
21433                        buffer_snapshot.clip_point(*position, Bias::Left)
21434                    };
21435                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
21436                    new_selections_by_buffer.insert(
21437                        buffer,
21438                        (
21439                            vec![jump_to_offset..jump_to_offset],
21440                            Some(*line_offset_from_top),
21441                        ),
21442                    );
21443                }
21444            }
21445            Some(JumpData::MultiBufferRow {
21446                row,
21447                line_offset_from_top,
21448            }) => {
21449                let point = MultiBufferPoint::new(row.0, 0);
21450                if let Some((buffer, buffer_point, _)) =
21451                    self.buffer.read(cx).point_to_buffer_point(point, cx)
21452                {
21453                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
21454                    new_selections_by_buffer
21455                        .entry(buffer)
21456                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
21457                        .0
21458                        .push(buffer_offset..buffer_offset)
21459                }
21460            }
21461            None => {
21462                let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
21463                let multi_buffer = self.buffer.read(cx);
21464                for selection in selections {
21465                    for (snapshot, range, _, anchor) in multi_buffer
21466                        .snapshot(cx)
21467                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
21468                    {
21469                        if let Some(anchor) = anchor {
21470                            let Some(buffer_handle) = multi_buffer.buffer_for_anchor(anchor, cx)
21471                            else {
21472                                continue;
21473                            };
21474                            let offset = text::ToOffset::to_offset(
21475                                &anchor.text_anchor,
21476                                &buffer_handle.read(cx).snapshot(),
21477                            );
21478                            let range = offset..offset;
21479                            new_selections_by_buffer
21480                                .entry(buffer_handle)
21481                                .or_insert((Vec::new(), None))
21482                                .0
21483                                .push(range)
21484                        } else {
21485                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
21486                            else {
21487                                continue;
21488                            };
21489                            new_selections_by_buffer
21490                                .entry(buffer_handle)
21491                                .or_insert((Vec::new(), None))
21492                                .0
21493                                .push(range)
21494                        }
21495                    }
21496                }
21497            }
21498        }
21499
21500        new_selections_by_buffer
21501            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
21502
21503        if new_selections_by_buffer.is_empty() {
21504            return;
21505        }
21506
21507        // We defer the pane interaction because we ourselves are a workspace item
21508        // and activating a new item causes the pane to call a method on us reentrantly,
21509        // which panics if we're on the stack.
21510        window.defer(cx, move |window, cx| {
21511            workspace.update(cx, |workspace, cx| {
21512                let pane = if split {
21513                    workspace.adjacent_pane(window, cx)
21514                } else {
21515                    workspace.active_pane().clone()
21516                };
21517
21518                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
21519                    let editor = buffer
21520                        .read(cx)
21521                        .file()
21522                        .is_none()
21523                        .then(|| {
21524                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
21525                            // so `workspace.open_project_item` will never find them, always opening a new editor.
21526                            // Instead, we try to activate the existing editor in the pane first.
21527                            let (editor, pane_item_index) =
21528                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
21529                                    let editor = item.downcast::<Editor>()?;
21530                                    let singleton_buffer =
21531                                        editor.read(cx).buffer().read(cx).as_singleton()?;
21532                                    if singleton_buffer == buffer {
21533                                        Some((editor, i))
21534                                    } else {
21535                                        None
21536                                    }
21537                                })?;
21538                            pane.update(cx, |pane, cx| {
21539                                pane.activate_item(pane_item_index, true, true, window, cx)
21540                            });
21541                            Some(editor)
21542                        })
21543                        .flatten()
21544                        .unwrap_or_else(|| {
21545                            workspace.open_project_item::<Self>(
21546                                pane.clone(),
21547                                buffer,
21548                                true,
21549                                true,
21550                                window,
21551                                cx,
21552                            )
21553                        });
21554
21555                    editor.update(cx, |editor, cx| {
21556                        let autoscroll = match scroll_offset {
21557                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
21558                            None => Autoscroll::newest(),
21559                        };
21560                        let nav_history = editor.nav_history.take();
21561                        editor.change_selections(
21562                            SelectionEffects::scroll(autoscroll),
21563                            window,
21564                            cx,
21565                            |s| {
21566                                s.select_ranges(ranges);
21567                            },
21568                        );
21569                        editor.nav_history = nav_history;
21570                    });
21571                }
21572            })
21573        });
21574    }
21575
21576    // For now, don't allow opening excerpts in buffers that aren't backed by
21577    // regular project files.
21578    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
21579        file.is_none_or(|file| project::File::from_dyn(Some(file)).is_some())
21580    }
21581
21582    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
21583        let snapshot = self.buffer.read(cx).read(cx);
21584        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
21585        Some(
21586            ranges
21587                .iter()
21588                .map(move |range| {
21589                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
21590                })
21591                .collect(),
21592        )
21593    }
21594
21595    fn selection_replacement_ranges(
21596        &self,
21597        range: Range<OffsetUtf16>,
21598        cx: &mut App,
21599    ) -> Vec<Range<OffsetUtf16>> {
21600        let selections = self
21601            .selections
21602            .all::<OffsetUtf16>(&self.display_snapshot(cx));
21603        let newest_selection = selections
21604            .iter()
21605            .max_by_key(|selection| selection.id)
21606            .unwrap();
21607        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
21608        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
21609        let snapshot = self.buffer.read(cx).read(cx);
21610        selections
21611            .into_iter()
21612            .map(|mut selection| {
21613                selection.start.0 =
21614                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
21615                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
21616                snapshot.clip_offset_utf16(selection.start, Bias::Left)
21617                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
21618            })
21619            .collect()
21620    }
21621
21622    fn report_editor_event(
21623        &self,
21624        reported_event: ReportEditorEvent,
21625        file_extension: Option<String>,
21626        cx: &App,
21627    ) {
21628        if cfg!(any(test, feature = "test-support")) {
21629            return;
21630        }
21631
21632        let Some(project) = &self.project else { return };
21633
21634        // If None, we are in a file without an extension
21635        let file = self
21636            .buffer
21637            .read(cx)
21638            .as_singleton()
21639            .and_then(|b| b.read(cx).file());
21640        let file_extension = file_extension.or(file
21641            .as_ref()
21642            .and_then(|file| Path::new(file.file_name(cx)).extension())
21643            .and_then(|e| e.to_str())
21644            .map(|a| a.to_string()));
21645
21646        let vim_mode = vim_flavor(cx).is_some();
21647
21648        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
21649        let copilot_enabled = edit_predictions_provider
21650            == language::language_settings::EditPredictionProvider::Copilot;
21651        let copilot_enabled_for_language = self
21652            .buffer
21653            .read(cx)
21654            .language_settings(cx)
21655            .show_edit_predictions;
21656
21657        let project = project.read(cx);
21658        let event_type = reported_event.event_type();
21659
21660        if let ReportEditorEvent::Saved { auto_saved } = reported_event {
21661            telemetry::event!(
21662                event_type,
21663                type = if auto_saved {"autosave"} else {"manual"},
21664                file_extension,
21665                vim_mode,
21666                copilot_enabled,
21667                copilot_enabled_for_language,
21668                edit_predictions_provider,
21669                is_via_ssh = project.is_via_remote_server(),
21670            );
21671        } else {
21672            telemetry::event!(
21673                event_type,
21674                file_extension,
21675                vim_mode,
21676                copilot_enabled,
21677                copilot_enabled_for_language,
21678                edit_predictions_provider,
21679                is_via_ssh = project.is_via_remote_server(),
21680            );
21681        };
21682    }
21683
21684    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
21685    /// with each line being an array of {text, highlight} objects.
21686    fn copy_highlight_json(
21687        &mut self,
21688        _: &CopyHighlightJson,
21689        window: &mut Window,
21690        cx: &mut Context<Self>,
21691    ) {
21692        #[derive(Serialize)]
21693        struct Chunk<'a> {
21694            text: String,
21695            highlight: Option<&'a str>,
21696        }
21697
21698        let snapshot = self.buffer.read(cx).snapshot(cx);
21699        let range = self
21700            .selected_text_range(false, window, cx)
21701            .and_then(|selection| {
21702                if selection.range.is_empty() {
21703                    None
21704                } else {
21705                    Some(
21706                        snapshot.offset_utf16_to_offset(OffsetUtf16(selection.range.start))
21707                            ..snapshot.offset_utf16_to_offset(OffsetUtf16(selection.range.end)),
21708                    )
21709                }
21710            })
21711            .unwrap_or_else(|| 0..snapshot.len());
21712
21713        let chunks = snapshot.chunks(range, true);
21714        let mut lines = Vec::new();
21715        let mut line: VecDeque<Chunk> = VecDeque::new();
21716
21717        let Some(style) = self.style.as_ref() else {
21718            return;
21719        };
21720
21721        for chunk in chunks {
21722            let highlight = chunk
21723                .syntax_highlight_id
21724                .and_then(|id| id.name(&style.syntax));
21725            let mut chunk_lines = chunk.text.split('\n').peekable();
21726            while let Some(text) = chunk_lines.next() {
21727                let mut merged_with_last_token = false;
21728                if let Some(last_token) = line.back_mut()
21729                    && last_token.highlight == highlight
21730                {
21731                    last_token.text.push_str(text);
21732                    merged_with_last_token = true;
21733                }
21734
21735                if !merged_with_last_token {
21736                    line.push_back(Chunk {
21737                        text: text.into(),
21738                        highlight,
21739                    });
21740                }
21741
21742                if chunk_lines.peek().is_some() {
21743                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
21744                        line.pop_front();
21745                    }
21746                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
21747                        line.pop_back();
21748                    }
21749
21750                    lines.push(mem::take(&mut line));
21751                }
21752            }
21753        }
21754
21755        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
21756            return;
21757        };
21758        cx.write_to_clipboard(ClipboardItem::new_string(lines));
21759    }
21760
21761    pub fn open_context_menu(
21762        &mut self,
21763        _: &OpenContextMenu,
21764        window: &mut Window,
21765        cx: &mut Context<Self>,
21766    ) {
21767        self.request_autoscroll(Autoscroll::newest(), cx);
21768        let position = self
21769            .selections
21770            .newest_display(&self.display_snapshot(cx))
21771            .start;
21772        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
21773    }
21774
21775    pub fn replay_insert_event(
21776        &mut self,
21777        text: &str,
21778        relative_utf16_range: Option<Range<isize>>,
21779        window: &mut Window,
21780        cx: &mut Context<Self>,
21781    ) {
21782        if !self.input_enabled {
21783            cx.emit(EditorEvent::InputIgnored { text: text.into() });
21784            return;
21785        }
21786        if let Some(relative_utf16_range) = relative_utf16_range {
21787            let selections = self
21788                .selections
21789                .all::<OffsetUtf16>(&self.display_snapshot(cx));
21790            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21791                let new_ranges = selections.into_iter().map(|range| {
21792                    let start = OffsetUtf16(
21793                        range
21794                            .head()
21795                            .0
21796                            .saturating_add_signed(relative_utf16_range.start),
21797                    );
21798                    let end = OffsetUtf16(
21799                        range
21800                            .head()
21801                            .0
21802                            .saturating_add_signed(relative_utf16_range.end),
21803                    );
21804                    start..end
21805                });
21806                s.select_ranges(new_ranges);
21807            });
21808        }
21809
21810        self.handle_input(text, window, cx);
21811    }
21812
21813    pub fn is_focused(&self, window: &Window) -> bool {
21814        self.focus_handle.is_focused(window)
21815    }
21816
21817    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21818        cx.emit(EditorEvent::Focused);
21819
21820        if let Some(descendant) = self
21821            .last_focused_descendant
21822            .take()
21823            .and_then(|descendant| descendant.upgrade())
21824        {
21825            window.focus(&descendant);
21826        } else {
21827            if let Some(blame) = self.blame.as_ref() {
21828                blame.update(cx, GitBlame::focus)
21829            }
21830
21831            self.blink_manager.update(cx, BlinkManager::enable);
21832            self.show_cursor_names(window, cx);
21833            self.buffer.update(cx, |buffer, cx| {
21834                buffer.finalize_last_transaction(cx);
21835                if self.leader_id.is_none() {
21836                    buffer.set_active_selections(
21837                        &self.selections.disjoint_anchors_arc(),
21838                        self.selections.line_mode(),
21839                        self.cursor_shape,
21840                        cx,
21841                    );
21842                }
21843            });
21844        }
21845    }
21846
21847    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
21848        cx.emit(EditorEvent::FocusedIn)
21849    }
21850
21851    fn handle_focus_out(
21852        &mut self,
21853        event: FocusOutEvent,
21854        _window: &mut Window,
21855        cx: &mut Context<Self>,
21856    ) {
21857        if event.blurred != self.focus_handle {
21858            self.last_focused_descendant = Some(event.blurred);
21859        }
21860        self.selection_drag_state = SelectionDragState::None;
21861        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
21862    }
21863
21864    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21865        self.blink_manager.update(cx, BlinkManager::disable);
21866        self.buffer
21867            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
21868
21869        if let Some(blame) = self.blame.as_ref() {
21870            blame.update(cx, GitBlame::blur)
21871        }
21872        if !self.hover_state.focused(window, cx) {
21873            hide_hover(self, cx);
21874        }
21875        if !self
21876            .context_menu
21877            .borrow()
21878            .as_ref()
21879            .is_some_and(|context_menu| context_menu.focused(window, cx))
21880        {
21881            self.hide_context_menu(window, cx);
21882        }
21883        self.take_active_edit_prediction(cx);
21884        cx.emit(EditorEvent::Blurred);
21885        cx.notify();
21886    }
21887
21888    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21889        let mut pending: String = window
21890            .pending_input_keystrokes()
21891            .into_iter()
21892            .flatten()
21893            .filter_map(|keystroke| {
21894                if keystroke.modifiers.is_subset_of(&Modifiers::shift()) {
21895                    keystroke.key_char.clone()
21896                } else {
21897                    None
21898                }
21899            })
21900            .collect();
21901
21902        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
21903            pending = "".to_string();
21904        }
21905
21906        let existing_pending = self
21907            .text_highlights::<PendingInput>(cx)
21908            .map(|(_, ranges)| ranges.to_vec());
21909        if existing_pending.is_none() && pending.is_empty() {
21910            return;
21911        }
21912        let transaction =
21913            self.transact(window, cx, |this, window, cx| {
21914                let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
21915                let edits = selections
21916                    .iter()
21917                    .map(|selection| (selection.end..selection.end, pending.clone()));
21918                this.edit(edits, cx);
21919                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21920                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
21921                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
21922                    }));
21923                });
21924                if let Some(existing_ranges) = existing_pending {
21925                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
21926                    this.edit(edits, cx);
21927                }
21928            });
21929
21930        let snapshot = self.snapshot(window, cx);
21931        let ranges = self
21932            .selections
21933            .all::<usize>(&snapshot.display_snapshot)
21934            .into_iter()
21935            .map(|selection| {
21936                snapshot.buffer_snapshot().anchor_after(selection.end)
21937                    ..snapshot
21938                        .buffer_snapshot()
21939                        .anchor_before(selection.end + pending.len())
21940            })
21941            .collect();
21942
21943        if pending.is_empty() {
21944            self.clear_highlights::<PendingInput>(cx);
21945        } else {
21946            self.highlight_text::<PendingInput>(
21947                ranges,
21948                HighlightStyle {
21949                    underline: Some(UnderlineStyle {
21950                        thickness: px(1.),
21951                        color: None,
21952                        wavy: false,
21953                    }),
21954                    ..Default::default()
21955                },
21956                cx,
21957            );
21958        }
21959
21960        self.ime_transaction = self.ime_transaction.or(transaction);
21961        if let Some(transaction) = self.ime_transaction {
21962            self.buffer.update(cx, |buffer, cx| {
21963                buffer.group_until_transaction(transaction, cx);
21964            });
21965        }
21966
21967        if self.text_highlights::<PendingInput>(cx).is_none() {
21968            self.ime_transaction.take();
21969        }
21970    }
21971
21972    pub fn register_action_renderer(
21973        &mut self,
21974        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
21975    ) -> Subscription {
21976        let id = self.next_editor_action_id.post_inc();
21977        self.editor_actions
21978            .borrow_mut()
21979            .insert(id, Box::new(listener));
21980
21981        let editor_actions = self.editor_actions.clone();
21982        Subscription::new(move || {
21983            editor_actions.borrow_mut().remove(&id);
21984        })
21985    }
21986
21987    pub fn register_action<A: Action>(
21988        &mut self,
21989        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
21990    ) -> Subscription {
21991        let id = self.next_editor_action_id.post_inc();
21992        let listener = Arc::new(listener);
21993        self.editor_actions.borrow_mut().insert(
21994            id,
21995            Box::new(move |_, window, _| {
21996                let listener = listener.clone();
21997                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
21998                    let action = action.downcast_ref().unwrap();
21999                    if phase == DispatchPhase::Bubble {
22000                        listener(action, window, cx)
22001                    }
22002                })
22003            }),
22004        );
22005
22006        let editor_actions = self.editor_actions.clone();
22007        Subscription::new(move || {
22008            editor_actions.borrow_mut().remove(&id);
22009        })
22010    }
22011
22012    pub fn file_header_size(&self) -> u32 {
22013        FILE_HEADER_HEIGHT
22014    }
22015
22016    pub fn restore(
22017        &mut self,
22018        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
22019        window: &mut Window,
22020        cx: &mut Context<Self>,
22021    ) {
22022        let workspace = self.workspace();
22023        let project = self.project();
22024        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
22025            let mut tasks = Vec::new();
22026            for (buffer_id, changes) in revert_changes {
22027                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
22028                    buffer.update(cx, |buffer, cx| {
22029                        buffer.edit(
22030                            changes
22031                                .into_iter()
22032                                .map(|(range, text)| (range, text.to_string())),
22033                            None,
22034                            cx,
22035                        );
22036                    });
22037
22038                    if let Some(project) =
22039                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
22040                    {
22041                        project.update(cx, |project, cx| {
22042                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
22043                        })
22044                    }
22045                }
22046            }
22047            tasks
22048        });
22049        cx.spawn_in(window, async move |_, cx| {
22050            for (buffer, task) in save_tasks {
22051                let result = task.await;
22052                if result.is_err() {
22053                    let Some(path) = buffer
22054                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
22055                        .ok()
22056                    else {
22057                        continue;
22058                    };
22059                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
22060                        let Some(task) = cx
22061                            .update_window_entity(workspace, |workspace, window, cx| {
22062                                workspace
22063                                    .open_path_preview(path, None, false, false, false, window, cx)
22064                            })
22065                            .ok()
22066                        else {
22067                            continue;
22068                        };
22069                        task.await.log_err();
22070                    }
22071                }
22072            }
22073        })
22074        .detach();
22075        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
22076            selections.refresh()
22077        });
22078    }
22079
22080    pub fn to_pixel_point(
22081        &self,
22082        source: multi_buffer::Anchor,
22083        editor_snapshot: &EditorSnapshot,
22084        window: &mut Window,
22085    ) -> Option<gpui::Point<Pixels>> {
22086        let source_point = source.to_display_point(editor_snapshot);
22087        self.display_to_pixel_point(source_point, editor_snapshot, window)
22088    }
22089
22090    pub fn display_to_pixel_point(
22091        &self,
22092        source: DisplayPoint,
22093        editor_snapshot: &EditorSnapshot,
22094        window: &mut Window,
22095    ) -> Option<gpui::Point<Pixels>> {
22096        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
22097        let text_layout_details = self.text_layout_details(window);
22098        let scroll_top = text_layout_details
22099            .scroll_anchor
22100            .scroll_position(editor_snapshot)
22101            .y;
22102
22103        if source.row().as_f64() < scroll_top.floor() {
22104            return None;
22105        }
22106        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
22107        let source_y = line_height * (source.row().as_f64() - scroll_top) as f32;
22108        Some(gpui::Point::new(source_x, source_y))
22109    }
22110
22111    pub fn has_visible_completions_menu(&self) -> bool {
22112        !self.edit_prediction_preview_is_active()
22113            && self.context_menu.borrow().as_ref().is_some_and(|menu| {
22114                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
22115            })
22116    }
22117
22118    pub fn register_addon<T: Addon>(&mut self, instance: T) {
22119        if self.mode.is_minimap() {
22120            return;
22121        }
22122        self.addons
22123            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
22124    }
22125
22126    pub fn unregister_addon<T: Addon>(&mut self) {
22127        self.addons.remove(&std::any::TypeId::of::<T>());
22128    }
22129
22130    pub fn addon<T: Addon>(&self) -> Option<&T> {
22131        let type_id = std::any::TypeId::of::<T>();
22132        self.addons
22133            .get(&type_id)
22134            .and_then(|item| item.to_any().downcast_ref::<T>())
22135    }
22136
22137    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
22138        let type_id = std::any::TypeId::of::<T>();
22139        self.addons
22140            .get_mut(&type_id)
22141            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
22142    }
22143
22144    fn character_dimensions(&self, window: &mut Window) -> CharacterDimensions {
22145        let text_layout_details = self.text_layout_details(window);
22146        let style = &text_layout_details.editor_style;
22147        let font_id = window.text_system().resolve_font(&style.text.font());
22148        let font_size = style.text.font_size.to_pixels(window.rem_size());
22149        let line_height = style.text.line_height_in_pixels(window.rem_size());
22150        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
22151        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
22152
22153        CharacterDimensions {
22154            em_width,
22155            em_advance,
22156            line_height,
22157        }
22158    }
22159
22160    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
22161        self.load_diff_task.clone()
22162    }
22163
22164    fn read_metadata_from_db(
22165        &mut self,
22166        item_id: u64,
22167        workspace_id: WorkspaceId,
22168        window: &mut Window,
22169        cx: &mut Context<Editor>,
22170    ) {
22171        if self.buffer_kind(cx) == ItemBufferKind::Singleton
22172            && !self.mode.is_minimap()
22173            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
22174        {
22175            let buffer_snapshot = OnceCell::new();
22176
22177            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err()
22178                && !folds.is_empty()
22179            {
22180                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
22181                self.fold_ranges(
22182                    folds
22183                        .into_iter()
22184                        .map(|(start, end)| {
22185                            snapshot.clip_offset(start, Bias::Left)
22186                                ..snapshot.clip_offset(end, Bias::Right)
22187                        })
22188                        .collect(),
22189                    false,
22190                    window,
22191                    cx,
22192                );
22193            }
22194
22195            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err()
22196                && !selections.is_empty()
22197            {
22198                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
22199                // skip adding the initial selection to selection history
22200                self.selection_history.mode = SelectionHistoryMode::Skipping;
22201                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
22202                    s.select_ranges(selections.into_iter().map(|(start, end)| {
22203                        snapshot.clip_offset(start, Bias::Left)
22204                            ..snapshot.clip_offset(end, Bias::Right)
22205                    }));
22206                });
22207                self.selection_history.mode = SelectionHistoryMode::Normal;
22208            };
22209        }
22210
22211        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
22212    }
22213
22214    fn update_lsp_data(
22215        &mut self,
22216        for_buffer: Option<BufferId>,
22217        window: &mut Window,
22218        cx: &mut Context<'_, Self>,
22219    ) {
22220        self.pull_diagnostics(for_buffer, window, cx);
22221        self.refresh_colors_for_visible_range(for_buffer, window, cx);
22222    }
22223
22224    fn register_visible_buffers(&mut self, cx: &mut Context<Self>) {
22225        if self.ignore_lsp_data() {
22226            return;
22227        }
22228        for (_, (visible_buffer, _, _)) in self.visible_excerpts(cx) {
22229            self.register_buffer(visible_buffer.read(cx).remote_id(), cx);
22230        }
22231    }
22232
22233    fn register_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
22234        if self.ignore_lsp_data() {
22235            return;
22236        }
22237
22238        if !self.registered_buffers.contains_key(&buffer_id)
22239            && let Some(project) = self.project.as_ref()
22240        {
22241            if let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) {
22242                project.update(cx, |project, cx| {
22243                    self.registered_buffers.insert(
22244                        buffer_id,
22245                        project.register_buffer_with_language_servers(&buffer, cx),
22246                    );
22247                });
22248            } else {
22249                self.registered_buffers.remove(&buffer_id);
22250            }
22251        }
22252    }
22253
22254    fn ignore_lsp_data(&self) -> bool {
22255        // `ActiveDiagnostic::All` is a special mode where editor's diagnostics are managed by the external view,
22256        // skip any LSP updates for it.
22257        self.active_diagnostics == ActiveDiagnostic::All || !self.mode().is_full()
22258    }
22259}
22260
22261fn edit_for_markdown_paste<'a>(
22262    buffer: &MultiBufferSnapshot,
22263    range: Range<usize>,
22264    to_insert: &'a str,
22265    url: Option<url::Url>,
22266) -> (Range<usize>, Cow<'a, str>) {
22267    if url.is_none() {
22268        return (range, Cow::Borrowed(to_insert));
22269    };
22270
22271    let old_text = buffer.text_for_range(range.clone()).collect::<String>();
22272
22273    let new_text = if range.is_empty() || url::Url::parse(&old_text).is_ok() {
22274        Cow::Borrowed(to_insert)
22275    } else {
22276        Cow::Owned(format!("[{old_text}]({to_insert})"))
22277    };
22278    (range, new_text)
22279}
22280
22281#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
22282pub enum VimFlavor {
22283    Vim,
22284    Helix,
22285}
22286
22287pub fn vim_flavor(cx: &App) -> Option<VimFlavor> {
22288    if vim_mode_setting::HelixModeSetting::try_get(cx)
22289        .map(|helix_mode| helix_mode.0)
22290        .unwrap_or(false)
22291    {
22292        Some(VimFlavor::Helix)
22293    } else if vim_mode_setting::VimModeSetting::try_get(cx)
22294        .map(|vim_mode| vim_mode.0)
22295        .unwrap_or(false)
22296    {
22297        Some(VimFlavor::Vim)
22298    } else {
22299        None // neither vim nor helix mode
22300    }
22301}
22302
22303fn process_completion_for_edit(
22304    completion: &Completion,
22305    intent: CompletionIntent,
22306    buffer: &Entity<Buffer>,
22307    cursor_position: &text::Anchor,
22308    cx: &mut Context<Editor>,
22309) -> CompletionEdit {
22310    let buffer = buffer.read(cx);
22311    let buffer_snapshot = buffer.snapshot();
22312    let (snippet, new_text) = if completion.is_snippet() {
22313        let mut snippet_source = completion.new_text.clone();
22314        // Workaround for typescript language server issues so that methods don't expand within
22315        // strings and functions with type expressions. The previous point is used because the query
22316        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
22317        let previous_point = text::ToPoint::to_point(cursor_position, &buffer_snapshot);
22318        let previous_point = if previous_point.column > 0 {
22319            cursor_position.to_previous_offset(&buffer_snapshot)
22320        } else {
22321            cursor_position.to_offset(&buffer_snapshot)
22322        };
22323        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point)
22324            && scope.prefers_label_for_snippet_in_completion()
22325            && let Some(label) = completion.label()
22326            && matches!(
22327                completion.kind(),
22328                Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
22329            )
22330        {
22331            snippet_source = label;
22332        }
22333        match Snippet::parse(&snippet_source).log_err() {
22334            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
22335            None => (None, completion.new_text.clone()),
22336        }
22337    } else {
22338        (None, completion.new_text.clone())
22339    };
22340
22341    let mut range_to_replace = {
22342        let replace_range = &completion.replace_range;
22343        if let CompletionSource::Lsp {
22344            insert_range: Some(insert_range),
22345            ..
22346        } = &completion.source
22347        {
22348            debug_assert_eq!(
22349                insert_range.start, replace_range.start,
22350                "insert_range and replace_range should start at the same position"
22351            );
22352            debug_assert!(
22353                insert_range
22354                    .start
22355                    .cmp(cursor_position, &buffer_snapshot)
22356                    .is_le(),
22357                "insert_range should start before or at cursor position"
22358            );
22359            debug_assert!(
22360                replace_range
22361                    .start
22362                    .cmp(cursor_position, &buffer_snapshot)
22363                    .is_le(),
22364                "replace_range should start before or at cursor position"
22365            );
22366
22367            let should_replace = match intent {
22368                CompletionIntent::CompleteWithInsert => false,
22369                CompletionIntent::CompleteWithReplace => true,
22370                CompletionIntent::Complete | CompletionIntent::Compose => {
22371                    let insert_mode =
22372                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
22373                            .completions
22374                            .lsp_insert_mode;
22375                    match insert_mode {
22376                        LspInsertMode::Insert => false,
22377                        LspInsertMode::Replace => true,
22378                        LspInsertMode::ReplaceSubsequence => {
22379                            let mut text_to_replace = buffer.chars_for_range(
22380                                buffer.anchor_before(replace_range.start)
22381                                    ..buffer.anchor_after(replace_range.end),
22382                            );
22383                            let mut current_needle = text_to_replace.next();
22384                            for haystack_ch in completion.label.text.chars() {
22385                                if let Some(needle_ch) = current_needle
22386                                    && haystack_ch.eq_ignore_ascii_case(&needle_ch)
22387                                {
22388                                    current_needle = text_to_replace.next();
22389                                }
22390                            }
22391                            current_needle.is_none()
22392                        }
22393                        LspInsertMode::ReplaceSuffix => {
22394                            if replace_range
22395                                .end
22396                                .cmp(cursor_position, &buffer_snapshot)
22397                                .is_gt()
22398                            {
22399                                let range_after_cursor = *cursor_position..replace_range.end;
22400                                let text_after_cursor = buffer
22401                                    .text_for_range(
22402                                        buffer.anchor_before(range_after_cursor.start)
22403                                            ..buffer.anchor_after(range_after_cursor.end),
22404                                    )
22405                                    .collect::<String>()
22406                                    .to_ascii_lowercase();
22407                                completion
22408                                    .label
22409                                    .text
22410                                    .to_ascii_lowercase()
22411                                    .ends_with(&text_after_cursor)
22412                            } else {
22413                                true
22414                            }
22415                        }
22416                    }
22417                }
22418            };
22419
22420            if should_replace {
22421                replace_range.clone()
22422            } else {
22423                insert_range.clone()
22424            }
22425        } else {
22426            replace_range.clone()
22427        }
22428    };
22429
22430    if range_to_replace
22431        .end
22432        .cmp(cursor_position, &buffer_snapshot)
22433        .is_lt()
22434    {
22435        range_to_replace.end = *cursor_position;
22436    }
22437
22438    CompletionEdit {
22439        new_text,
22440        replace_range: range_to_replace.to_offset(buffer),
22441        snippet,
22442    }
22443}
22444
22445struct CompletionEdit {
22446    new_text: String,
22447    replace_range: Range<usize>,
22448    snippet: Option<Snippet>,
22449}
22450
22451fn insert_extra_newline_brackets(
22452    buffer: &MultiBufferSnapshot,
22453    range: Range<usize>,
22454    language: &language::LanguageScope,
22455) -> bool {
22456    let leading_whitespace_len = buffer
22457        .reversed_chars_at(range.start)
22458        .take_while(|c| c.is_whitespace() && *c != '\n')
22459        .map(|c| c.len_utf8())
22460        .sum::<usize>();
22461    let trailing_whitespace_len = buffer
22462        .chars_at(range.end)
22463        .take_while(|c| c.is_whitespace() && *c != '\n')
22464        .map(|c| c.len_utf8())
22465        .sum::<usize>();
22466    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
22467
22468    language.brackets().any(|(pair, enabled)| {
22469        let pair_start = pair.start.trim_end();
22470        let pair_end = pair.end.trim_start();
22471
22472        enabled
22473            && pair.newline
22474            && buffer.contains_str_at(range.end, pair_end)
22475            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
22476    })
22477}
22478
22479fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
22480    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
22481        [(buffer, range, _)] => (*buffer, range.clone()),
22482        _ => return false,
22483    };
22484    let pair = {
22485        let mut result: Option<BracketMatch> = None;
22486
22487        for pair in buffer
22488            .all_bracket_ranges(range.clone())
22489            .filter(move |pair| {
22490                pair.open_range.start <= range.start && pair.close_range.end >= range.end
22491            })
22492        {
22493            let len = pair.close_range.end - pair.open_range.start;
22494
22495            if let Some(existing) = &result {
22496                let existing_len = existing.close_range.end - existing.open_range.start;
22497                if len > existing_len {
22498                    continue;
22499                }
22500            }
22501
22502            result = Some(pair);
22503        }
22504
22505        result
22506    };
22507    let Some(pair) = pair else {
22508        return false;
22509    };
22510    pair.newline_only
22511        && buffer
22512            .chars_for_range(pair.open_range.end..range.start)
22513            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
22514            .all(|c| c.is_whitespace() && c != '\n')
22515}
22516
22517fn update_uncommitted_diff_for_buffer(
22518    editor: Entity<Editor>,
22519    project: &Entity<Project>,
22520    buffers: impl IntoIterator<Item = Entity<Buffer>>,
22521    buffer: Entity<MultiBuffer>,
22522    cx: &mut App,
22523) -> Task<()> {
22524    let mut tasks = Vec::new();
22525    project.update(cx, |project, cx| {
22526        for buffer in buffers {
22527            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
22528                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
22529            }
22530        }
22531    });
22532    cx.spawn(async move |cx| {
22533        let diffs = future::join_all(tasks).await;
22534        if editor
22535            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
22536            .unwrap_or(false)
22537        {
22538            return;
22539        }
22540
22541        buffer
22542            .update(cx, |buffer, cx| {
22543                for diff in diffs.into_iter().flatten() {
22544                    buffer.add_diff(diff, cx);
22545                }
22546            })
22547            .ok();
22548    })
22549}
22550
22551fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
22552    let tab_size = tab_size.get() as usize;
22553    let mut width = offset;
22554
22555    for ch in text.chars() {
22556        width += if ch == '\t' {
22557            tab_size - (width % tab_size)
22558        } else {
22559            1
22560        };
22561    }
22562
22563    width - offset
22564}
22565
22566#[cfg(test)]
22567mod tests {
22568    use super::*;
22569
22570    #[test]
22571    fn test_string_size_with_expanded_tabs() {
22572        let nz = |val| NonZeroU32::new(val).unwrap();
22573        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
22574        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
22575        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
22576        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
22577        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
22578        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
22579        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
22580        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
22581    }
22582}
22583
22584/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
22585struct WordBreakingTokenizer<'a> {
22586    input: &'a str,
22587}
22588
22589impl<'a> WordBreakingTokenizer<'a> {
22590    fn new(input: &'a str) -> Self {
22591        Self { input }
22592    }
22593}
22594
22595fn is_char_ideographic(ch: char) -> bool {
22596    use unicode_script::Script::*;
22597    use unicode_script::UnicodeScript;
22598    matches!(ch.script(), Han | Tangut | Yi)
22599}
22600
22601fn is_grapheme_ideographic(text: &str) -> bool {
22602    text.chars().any(is_char_ideographic)
22603}
22604
22605fn is_grapheme_whitespace(text: &str) -> bool {
22606    text.chars().any(|x| x.is_whitespace())
22607}
22608
22609fn should_stay_with_preceding_ideograph(text: &str) -> bool {
22610    text.chars()
22611        .next()
22612        .is_some_and(|ch| matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…'))
22613}
22614
22615#[derive(PartialEq, Eq, Debug, Clone, Copy)]
22616enum WordBreakToken<'a> {
22617    Word { token: &'a str, grapheme_len: usize },
22618    InlineWhitespace { token: &'a str, grapheme_len: usize },
22619    Newline,
22620}
22621
22622impl<'a> Iterator for WordBreakingTokenizer<'a> {
22623    /// Yields a span, the count of graphemes in the token, and whether it was
22624    /// whitespace. Note that it also breaks at word boundaries.
22625    type Item = WordBreakToken<'a>;
22626
22627    fn next(&mut self) -> Option<Self::Item> {
22628        use unicode_segmentation::UnicodeSegmentation;
22629        if self.input.is_empty() {
22630            return None;
22631        }
22632
22633        let mut iter = self.input.graphemes(true).peekable();
22634        let mut offset = 0;
22635        let mut grapheme_len = 0;
22636        if let Some(first_grapheme) = iter.next() {
22637            let is_newline = first_grapheme == "\n";
22638            let is_whitespace = is_grapheme_whitespace(first_grapheme);
22639            offset += first_grapheme.len();
22640            grapheme_len += 1;
22641            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
22642                if let Some(grapheme) = iter.peek().copied()
22643                    && should_stay_with_preceding_ideograph(grapheme)
22644                {
22645                    offset += grapheme.len();
22646                    grapheme_len += 1;
22647                }
22648            } else {
22649                let mut words = self.input[offset..].split_word_bound_indices().peekable();
22650                let mut next_word_bound = words.peek().copied();
22651                if next_word_bound.is_some_and(|(i, _)| i == 0) {
22652                    next_word_bound = words.next();
22653                }
22654                while let Some(grapheme) = iter.peek().copied() {
22655                    if next_word_bound.is_some_and(|(i, _)| i == offset) {
22656                        break;
22657                    };
22658                    if is_grapheme_whitespace(grapheme) != is_whitespace
22659                        || (grapheme == "\n") != is_newline
22660                    {
22661                        break;
22662                    };
22663                    offset += grapheme.len();
22664                    grapheme_len += 1;
22665                    iter.next();
22666                }
22667            }
22668            let token = &self.input[..offset];
22669            self.input = &self.input[offset..];
22670            if token == "\n" {
22671                Some(WordBreakToken::Newline)
22672            } else if is_whitespace {
22673                Some(WordBreakToken::InlineWhitespace {
22674                    token,
22675                    grapheme_len,
22676                })
22677            } else {
22678                Some(WordBreakToken::Word {
22679                    token,
22680                    grapheme_len,
22681                })
22682            }
22683        } else {
22684            None
22685        }
22686    }
22687}
22688
22689#[test]
22690fn test_word_breaking_tokenizer() {
22691    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
22692        ("", &[]),
22693        ("  ", &[whitespace("  ", 2)]),
22694        ("Ʒ", &[word("Ʒ", 1)]),
22695        ("Ǽ", &[word("Ǽ", 1)]),
22696        ("", &[word("", 1)]),
22697        ("⋑⋑", &[word("⋑⋑", 2)]),
22698        (
22699            "原理,进而",
22700            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
22701        ),
22702        (
22703            "hello world",
22704            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
22705        ),
22706        (
22707            "hello, world",
22708            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
22709        ),
22710        (
22711            "  hello world",
22712            &[
22713                whitespace("  ", 2),
22714                word("hello", 5),
22715                whitespace(" ", 1),
22716                word("world", 5),
22717            ],
22718        ),
22719        (
22720            "这是什么 \n 钢笔",
22721            &[
22722                word("", 1),
22723                word("", 1),
22724                word("", 1),
22725                word("", 1),
22726                whitespace(" ", 1),
22727                newline(),
22728                whitespace(" ", 1),
22729                word("", 1),
22730                word("", 1),
22731            ],
22732        ),
22733        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
22734    ];
22735
22736    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
22737        WordBreakToken::Word {
22738            token,
22739            grapheme_len,
22740        }
22741    }
22742
22743    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
22744        WordBreakToken::InlineWhitespace {
22745            token,
22746            grapheme_len,
22747        }
22748    }
22749
22750    fn newline() -> WordBreakToken<'static> {
22751        WordBreakToken::Newline
22752    }
22753
22754    for (input, result) in tests {
22755        assert_eq!(
22756            WordBreakingTokenizer::new(input)
22757                .collect::<Vec<_>>()
22758                .as_slice(),
22759            *result,
22760        );
22761    }
22762}
22763
22764fn wrap_with_prefix(
22765    first_line_prefix: String,
22766    subsequent_lines_prefix: String,
22767    unwrapped_text: String,
22768    wrap_column: usize,
22769    tab_size: NonZeroU32,
22770    preserve_existing_whitespace: bool,
22771) -> String {
22772    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
22773    let subsequent_lines_prefix_len =
22774        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
22775    let mut wrapped_text = String::new();
22776    let mut current_line = first_line_prefix;
22777    let mut is_first_line = true;
22778
22779    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
22780    let mut current_line_len = first_line_prefix_len;
22781    let mut in_whitespace = false;
22782    for token in tokenizer {
22783        let have_preceding_whitespace = in_whitespace;
22784        match token {
22785            WordBreakToken::Word {
22786                token,
22787                grapheme_len,
22788            } => {
22789                in_whitespace = false;
22790                let current_prefix_len = if is_first_line {
22791                    first_line_prefix_len
22792                } else {
22793                    subsequent_lines_prefix_len
22794                };
22795                if current_line_len + grapheme_len > wrap_column
22796                    && current_line_len != current_prefix_len
22797                {
22798                    wrapped_text.push_str(current_line.trim_end());
22799                    wrapped_text.push('\n');
22800                    is_first_line = false;
22801                    current_line = subsequent_lines_prefix.clone();
22802                    current_line_len = subsequent_lines_prefix_len;
22803                }
22804                current_line.push_str(token);
22805                current_line_len += grapheme_len;
22806            }
22807            WordBreakToken::InlineWhitespace {
22808                mut token,
22809                mut grapheme_len,
22810            } => {
22811                in_whitespace = true;
22812                if have_preceding_whitespace && !preserve_existing_whitespace {
22813                    continue;
22814                }
22815                if !preserve_existing_whitespace {
22816                    // Keep a single whitespace grapheme as-is
22817                    if let Some(first) =
22818                        unicode_segmentation::UnicodeSegmentation::graphemes(token, true).next()
22819                    {
22820                        token = first;
22821                    } else {
22822                        token = " ";
22823                    }
22824                    grapheme_len = 1;
22825                }
22826                let current_prefix_len = if is_first_line {
22827                    first_line_prefix_len
22828                } else {
22829                    subsequent_lines_prefix_len
22830                };
22831                if current_line_len + grapheme_len > wrap_column {
22832                    wrapped_text.push_str(current_line.trim_end());
22833                    wrapped_text.push('\n');
22834                    is_first_line = false;
22835                    current_line = subsequent_lines_prefix.clone();
22836                    current_line_len = subsequent_lines_prefix_len;
22837                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
22838                    current_line.push_str(token);
22839                    current_line_len += grapheme_len;
22840                }
22841            }
22842            WordBreakToken::Newline => {
22843                in_whitespace = true;
22844                let current_prefix_len = if is_first_line {
22845                    first_line_prefix_len
22846                } else {
22847                    subsequent_lines_prefix_len
22848                };
22849                if preserve_existing_whitespace {
22850                    wrapped_text.push_str(current_line.trim_end());
22851                    wrapped_text.push('\n');
22852                    is_first_line = false;
22853                    current_line = subsequent_lines_prefix.clone();
22854                    current_line_len = subsequent_lines_prefix_len;
22855                } else if have_preceding_whitespace {
22856                    continue;
22857                } else if current_line_len + 1 > wrap_column
22858                    && current_line_len != current_prefix_len
22859                {
22860                    wrapped_text.push_str(current_line.trim_end());
22861                    wrapped_text.push('\n');
22862                    is_first_line = false;
22863                    current_line = subsequent_lines_prefix.clone();
22864                    current_line_len = subsequent_lines_prefix_len;
22865                } else if current_line_len != current_prefix_len {
22866                    current_line.push(' ');
22867                    current_line_len += 1;
22868                }
22869            }
22870        }
22871    }
22872
22873    if !current_line.is_empty() {
22874        wrapped_text.push_str(&current_line);
22875    }
22876    wrapped_text
22877}
22878
22879#[test]
22880fn test_wrap_with_prefix() {
22881    assert_eq!(
22882        wrap_with_prefix(
22883            "# ".to_string(),
22884            "# ".to_string(),
22885            "abcdefg".to_string(),
22886            4,
22887            NonZeroU32::new(4).unwrap(),
22888            false,
22889        ),
22890        "# abcdefg"
22891    );
22892    assert_eq!(
22893        wrap_with_prefix(
22894            "".to_string(),
22895            "".to_string(),
22896            "\thello world".to_string(),
22897            8,
22898            NonZeroU32::new(4).unwrap(),
22899            false,
22900        ),
22901        "hello\nworld"
22902    );
22903    assert_eq!(
22904        wrap_with_prefix(
22905            "// ".to_string(),
22906            "// ".to_string(),
22907            "xx \nyy zz aa bb cc".to_string(),
22908            12,
22909            NonZeroU32::new(4).unwrap(),
22910            false,
22911        ),
22912        "// xx yy zz\n// aa bb cc"
22913    );
22914    assert_eq!(
22915        wrap_with_prefix(
22916            String::new(),
22917            String::new(),
22918            "这是什么 \n 钢笔".to_string(),
22919            3,
22920            NonZeroU32::new(4).unwrap(),
22921            false,
22922        ),
22923        "这是什\n么 钢\n"
22924    );
22925    assert_eq!(
22926        wrap_with_prefix(
22927            String::new(),
22928            String::new(),
22929            format!("foo{}bar", '\u{2009}'), // thin space
22930            80,
22931            NonZeroU32::new(4).unwrap(),
22932            false,
22933        ),
22934        format!("foo{}bar", '\u{2009}')
22935    );
22936}
22937
22938pub trait CollaborationHub {
22939    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
22940    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
22941    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
22942}
22943
22944impl CollaborationHub for Entity<Project> {
22945    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
22946        self.read(cx).collaborators()
22947    }
22948
22949    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
22950        self.read(cx).user_store().read(cx).participant_indices()
22951    }
22952
22953    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
22954        let this = self.read(cx);
22955        let user_ids = this.collaborators().values().map(|c| c.user_id);
22956        this.user_store().read(cx).participant_names(user_ids, cx)
22957    }
22958}
22959
22960pub trait SemanticsProvider {
22961    fn hover(
22962        &self,
22963        buffer: &Entity<Buffer>,
22964        position: text::Anchor,
22965        cx: &mut App,
22966    ) -> Option<Task<Option<Vec<project::Hover>>>>;
22967
22968    fn inline_values(
22969        &self,
22970        buffer_handle: Entity<Buffer>,
22971        range: Range<text::Anchor>,
22972        cx: &mut App,
22973    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
22974
22975    fn applicable_inlay_chunks(
22976        &self,
22977        buffer: &Entity<Buffer>,
22978        ranges: &[Range<text::Anchor>],
22979        cx: &mut App,
22980    ) -> Vec<Range<BufferRow>>;
22981
22982    fn invalidate_inlay_hints(&self, for_buffers: &HashSet<BufferId>, cx: &mut App);
22983
22984    fn inlay_hints(
22985        &self,
22986        invalidate: InvalidationStrategy,
22987        buffer: Entity<Buffer>,
22988        ranges: Vec<Range<text::Anchor>>,
22989        known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
22990        cx: &mut App,
22991    ) -> Option<HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>>>;
22992
22993    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
22994
22995    fn document_highlights(
22996        &self,
22997        buffer: &Entity<Buffer>,
22998        position: text::Anchor,
22999        cx: &mut App,
23000    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
23001
23002    fn definitions(
23003        &self,
23004        buffer: &Entity<Buffer>,
23005        position: text::Anchor,
23006        kind: GotoDefinitionKind,
23007        cx: &mut App,
23008    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>>;
23009
23010    fn range_for_rename(
23011        &self,
23012        buffer: &Entity<Buffer>,
23013        position: text::Anchor,
23014        cx: &mut App,
23015    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
23016
23017    fn perform_rename(
23018        &self,
23019        buffer: &Entity<Buffer>,
23020        position: text::Anchor,
23021        new_name: String,
23022        cx: &mut App,
23023    ) -> Option<Task<Result<ProjectTransaction>>>;
23024}
23025
23026pub trait CompletionProvider {
23027    fn completions(
23028        &self,
23029        excerpt_id: ExcerptId,
23030        buffer: &Entity<Buffer>,
23031        buffer_position: text::Anchor,
23032        trigger: CompletionContext,
23033        window: &mut Window,
23034        cx: &mut Context<Editor>,
23035    ) -> Task<Result<Vec<CompletionResponse>>>;
23036
23037    fn resolve_completions(
23038        &self,
23039        _buffer: Entity<Buffer>,
23040        _completion_indices: Vec<usize>,
23041        _completions: Rc<RefCell<Box<[Completion]>>>,
23042        _cx: &mut Context<Editor>,
23043    ) -> Task<Result<bool>> {
23044        Task::ready(Ok(false))
23045    }
23046
23047    fn apply_additional_edits_for_completion(
23048        &self,
23049        _buffer: Entity<Buffer>,
23050        _completions: Rc<RefCell<Box<[Completion]>>>,
23051        _completion_index: usize,
23052        _push_to_history: bool,
23053        _cx: &mut Context<Editor>,
23054    ) -> Task<Result<Option<language::Transaction>>> {
23055        Task::ready(Ok(None))
23056    }
23057
23058    fn is_completion_trigger(
23059        &self,
23060        buffer: &Entity<Buffer>,
23061        position: language::Anchor,
23062        text: &str,
23063        trigger_in_words: bool,
23064        menu_is_open: bool,
23065        cx: &mut Context<Editor>,
23066    ) -> bool;
23067
23068    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
23069
23070    fn sort_completions(&self) -> bool {
23071        true
23072    }
23073
23074    fn filter_completions(&self) -> bool {
23075        true
23076    }
23077}
23078
23079pub trait CodeActionProvider {
23080    fn id(&self) -> Arc<str>;
23081
23082    fn code_actions(
23083        &self,
23084        buffer: &Entity<Buffer>,
23085        range: Range<text::Anchor>,
23086        window: &mut Window,
23087        cx: &mut App,
23088    ) -> Task<Result<Vec<CodeAction>>>;
23089
23090    fn apply_code_action(
23091        &self,
23092        buffer_handle: Entity<Buffer>,
23093        action: CodeAction,
23094        excerpt_id: ExcerptId,
23095        push_to_history: bool,
23096        window: &mut Window,
23097        cx: &mut App,
23098    ) -> Task<Result<ProjectTransaction>>;
23099}
23100
23101impl CodeActionProvider for Entity<Project> {
23102    fn id(&self) -> Arc<str> {
23103        "project".into()
23104    }
23105
23106    fn code_actions(
23107        &self,
23108        buffer: &Entity<Buffer>,
23109        range: Range<text::Anchor>,
23110        _window: &mut Window,
23111        cx: &mut App,
23112    ) -> Task<Result<Vec<CodeAction>>> {
23113        self.update(cx, |project, cx| {
23114            let code_lens_actions = project.code_lens_actions(buffer, range.clone(), cx);
23115            let code_actions = project.code_actions(buffer, range, None, cx);
23116            cx.background_spawn(async move {
23117                let (code_lens_actions, code_actions) = join(code_lens_actions, code_actions).await;
23118                Ok(code_lens_actions
23119                    .context("code lens fetch")?
23120                    .into_iter()
23121                    .flatten()
23122                    .chain(
23123                        code_actions
23124                            .context("code action fetch")?
23125                            .into_iter()
23126                            .flatten(),
23127                    )
23128                    .collect())
23129            })
23130        })
23131    }
23132
23133    fn apply_code_action(
23134        &self,
23135        buffer_handle: Entity<Buffer>,
23136        action: CodeAction,
23137        _excerpt_id: ExcerptId,
23138        push_to_history: bool,
23139        _window: &mut Window,
23140        cx: &mut App,
23141    ) -> Task<Result<ProjectTransaction>> {
23142        self.update(cx, |project, cx| {
23143            project.apply_code_action(buffer_handle, action, push_to_history, cx)
23144        })
23145    }
23146}
23147
23148fn snippet_completions(
23149    project: &Project,
23150    buffer: &Entity<Buffer>,
23151    buffer_position: text::Anchor,
23152    cx: &mut App,
23153) -> Task<Result<CompletionResponse>> {
23154    let languages = buffer.read(cx).languages_at(buffer_position);
23155    let snippet_store = project.snippets().read(cx);
23156
23157    let scopes: Vec<_> = languages
23158        .iter()
23159        .filter_map(|language| {
23160            let language_name = language.lsp_id();
23161            let snippets = snippet_store.snippets_for(Some(language_name), cx);
23162
23163            if snippets.is_empty() {
23164                None
23165            } else {
23166                Some((language.default_scope(), snippets))
23167            }
23168        })
23169        .collect();
23170
23171    if scopes.is_empty() {
23172        return Task::ready(Ok(CompletionResponse {
23173            completions: vec![],
23174            display_options: CompletionDisplayOptions::default(),
23175            is_incomplete: false,
23176        }));
23177    }
23178
23179    let snapshot = buffer.read(cx).text_snapshot();
23180    let executor = cx.background_executor().clone();
23181
23182    cx.background_spawn(async move {
23183        let mut is_incomplete = false;
23184        let mut completions: Vec<Completion> = Vec::new();
23185        for (scope, snippets) in scopes.into_iter() {
23186            let classifier =
23187                CharClassifier::new(Some(scope)).scope_context(Some(CharScopeContext::Completion));
23188
23189            const MAX_WORD_PREFIX_LEN: usize = 128;
23190            let last_word: String = snapshot
23191                .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
23192                .take(MAX_WORD_PREFIX_LEN)
23193                .take_while(|c| classifier.is_word(*c))
23194                .collect::<String>()
23195                .chars()
23196                .rev()
23197                .collect();
23198
23199            if last_word.is_empty() {
23200                return Ok(CompletionResponse {
23201                    completions: vec![],
23202                    display_options: CompletionDisplayOptions::default(),
23203                    is_incomplete: true,
23204                });
23205            }
23206
23207            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
23208            let to_lsp = |point: &text::Anchor| {
23209                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
23210                point_to_lsp(end)
23211            };
23212            let lsp_end = to_lsp(&buffer_position);
23213
23214            let candidates = snippets
23215                .iter()
23216                .enumerate()
23217                .flat_map(|(ix, snippet)| {
23218                    snippet
23219                        .prefix
23220                        .iter()
23221                        .map(move |prefix| StringMatchCandidate::new(ix, prefix))
23222                })
23223                .collect::<Vec<StringMatchCandidate>>();
23224
23225            const MAX_RESULTS: usize = 100;
23226            let mut matches = fuzzy::match_strings(
23227                &candidates,
23228                &last_word,
23229                last_word.chars().any(|c| c.is_uppercase()),
23230                true,
23231                MAX_RESULTS,
23232                &Default::default(),
23233                executor.clone(),
23234            )
23235            .await;
23236
23237            if matches.len() >= MAX_RESULTS {
23238                is_incomplete = true;
23239            }
23240
23241            // Remove all candidates where the query's start does not match the start of any word in the candidate
23242            if let Some(query_start) = last_word.chars().next() {
23243                matches.retain(|string_match| {
23244                    split_words(&string_match.string).any(|word| {
23245                        // Check that the first codepoint of the word as lowercase matches the first
23246                        // codepoint of the query as lowercase
23247                        word.chars()
23248                            .flat_map(|codepoint| codepoint.to_lowercase())
23249                            .zip(query_start.to_lowercase())
23250                            .all(|(word_cp, query_cp)| word_cp == query_cp)
23251                    })
23252                });
23253            }
23254
23255            let matched_strings = matches
23256                .into_iter()
23257                .map(|m| m.string)
23258                .collect::<HashSet<_>>();
23259
23260            completions.extend(snippets.iter().filter_map(|snippet| {
23261                let matching_prefix = snippet
23262                    .prefix
23263                    .iter()
23264                    .find(|prefix| matched_strings.contains(*prefix))?;
23265                let start = as_offset - last_word.len();
23266                let start = snapshot.anchor_before(start);
23267                let range = start..buffer_position;
23268                let lsp_start = to_lsp(&start);
23269                let lsp_range = lsp::Range {
23270                    start: lsp_start,
23271                    end: lsp_end,
23272                };
23273                Some(Completion {
23274                    replace_range: range,
23275                    new_text: snippet.body.clone(),
23276                    source: CompletionSource::Lsp {
23277                        insert_range: None,
23278                        server_id: LanguageServerId(usize::MAX),
23279                        resolved: true,
23280                        lsp_completion: Box::new(lsp::CompletionItem {
23281                            label: snippet.prefix.first().unwrap().clone(),
23282                            kind: Some(CompletionItemKind::SNIPPET),
23283                            label_details: snippet.description.as_ref().map(|description| {
23284                                lsp::CompletionItemLabelDetails {
23285                                    detail: Some(description.clone()),
23286                                    description: None,
23287                                }
23288                            }),
23289                            insert_text_format: Some(InsertTextFormat::SNIPPET),
23290                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
23291                                lsp::InsertReplaceEdit {
23292                                    new_text: snippet.body.clone(),
23293                                    insert: lsp_range,
23294                                    replace: lsp_range,
23295                                },
23296                            )),
23297                            filter_text: Some(snippet.body.clone()),
23298                            sort_text: Some(char::MAX.to_string()),
23299                            ..lsp::CompletionItem::default()
23300                        }),
23301                        lsp_defaults: None,
23302                    },
23303                    label: CodeLabel::plain(matching_prefix.clone(), None),
23304                    icon_path: None,
23305                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
23306                        single_line: snippet.name.clone().into(),
23307                        plain_text: snippet
23308                            .description
23309                            .clone()
23310                            .map(|description| description.into()),
23311                    }),
23312                    insert_text_mode: None,
23313                    confirm: None,
23314                })
23315            }))
23316        }
23317
23318        Ok(CompletionResponse {
23319            completions,
23320            display_options: CompletionDisplayOptions::default(),
23321            is_incomplete,
23322        })
23323    })
23324}
23325
23326impl CompletionProvider for Entity<Project> {
23327    fn completions(
23328        &self,
23329        _excerpt_id: ExcerptId,
23330        buffer: &Entity<Buffer>,
23331        buffer_position: text::Anchor,
23332        options: CompletionContext,
23333        _window: &mut Window,
23334        cx: &mut Context<Editor>,
23335    ) -> Task<Result<Vec<CompletionResponse>>> {
23336        self.update(cx, |project, cx| {
23337            let snippets = snippet_completions(project, buffer, buffer_position, cx);
23338            let project_completions = project.completions(buffer, buffer_position, options, cx);
23339            cx.background_spawn(async move {
23340                let mut responses = project_completions.await?;
23341                let snippets = snippets.await?;
23342                if !snippets.completions.is_empty() {
23343                    responses.push(snippets);
23344                }
23345                Ok(responses)
23346            })
23347        })
23348    }
23349
23350    fn resolve_completions(
23351        &self,
23352        buffer: Entity<Buffer>,
23353        completion_indices: Vec<usize>,
23354        completions: Rc<RefCell<Box<[Completion]>>>,
23355        cx: &mut Context<Editor>,
23356    ) -> Task<Result<bool>> {
23357        self.update(cx, |project, cx| {
23358            project.lsp_store().update(cx, |lsp_store, cx| {
23359                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
23360            })
23361        })
23362    }
23363
23364    fn apply_additional_edits_for_completion(
23365        &self,
23366        buffer: Entity<Buffer>,
23367        completions: Rc<RefCell<Box<[Completion]>>>,
23368        completion_index: usize,
23369        push_to_history: bool,
23370        cx: &mut Context<Editor>,
23371    ) -> Task<Result<Option<language::Transaction>>> {
23372        self.update(cx, |project, cx| {
23373            project.lsp_store().update(cx, |lsp_store, cx| {
23374                lsp_store.apply_additional_edits_for_completion(
23375                    buffer,
23376                    completions,
23377                    completion_index,
23378                    push_to_history,
23379                    cx,
23380                )
23381            })
23382        })
23383    }
23384
23385    fn is_completion_trigger(
23386        &self,
23387        buffer: &Entity<Buffer>,
23388        position: language::Anchor,
23389        text: &str,
23390        trigger_in_words: bool,
23391        menu_is_open: bool,
23392        cx: &mut Context<Editor>,
23393    ) -> bool {
23394        let mut chars = text.chars();
23395        let char = if let Some(char) = chars.next() {
23396            char
23397        } else {
23398            return false;
23399        };
23400        if chars.next().is_some() {
23401            return false;
23402        }
23403
23404        let buffer = buffer.read(cx);
23405        let snapshot = buffer.snapshot();
23406        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
23407            return false;
23408        }
23409        let classifier = snapshot
23410            .char_classifier_at(position)
23411            .scope_context(Some(CharScopeContext::Completion));
23412        if trigger_in_words && classifier.is_word(char) {
23413            return true;
23414        }
23415
23416        buffer.completion_triggers().contains(text)
23417    }
23418}
23419
23420impl SemanticsProvider for Entity<Project> {
23421    fn hover(
23422        &self,
23423        buffer: &Entity<Buffer>,
23424        position: text::Anchor,
23425        cx: &mut App,
23426    ) -> Option<Task<Option<Vec<project::Hover>>>> {
23427        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
23428    }
23429
23430    fn document_highlights(
23431        &self,
23432        buffer: &Entity<Buffer>,
23433        position: text::Anchor,
23434        cx: &mut App,
23435    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
23436        Some(self.update(cx, |project, cx| {
23437            project.document_highlights(buffer, position, cx)
23438        }))
23439    }
23440
23441    fn definitions(
23442        &self,
23443        buffer: &Entity<Buffer>,
23444        position: text::Anchor,
23445        kind: GotoDefinitionKind,
23446        cx: &mut App,
23447    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>> {
23448        Some(self.update(cx, |project, cx| match kind {
23449            GotoDefinitionKind::Symbol => project.definitions(buffer, position, cx),
23450            GotoDefinitionKind::Declaration => project.declarations(buffer, position, cx),
23451            GotoDefinitionKind::Type => project.type_definitions(buffer, position, cx),
23452            GotoDefinitionKind::Implementation => project.implementations(buffer, position, cx),
23453        }))
23454    }
23455
23456    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
23457        self.update(cx, |project, cx| {
23458            if project
23459                .active_debug_session(cx)
23460                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
23461            {
23462                return true;
23463            }
23464
23465            buffer.update(cx, |buffer, cx| {
23466                project.any_language_server_supports_inlay_hints(buffer, cx)
23467            })
23468        })
23469    }
23470
23471    fn inline_values(
23472        &self,
23473        buffer_handle: Entity<Buffer>,
23474        range: Range<text::Anchor>,
23475        cx: &mut App,
23476    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
23477        self.update(cx, |project, cx| {
23478            let (session, active_stack_frame) = project.active_debug_session(cx)?;
23479
23480            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
23481        })
23482    }
23483
23484    fn applicable_inlay_chunks(
23485        &self,
23486        buffer: &Entity<Buffer>,
23487        ranges: &[Range<text::Anchor>],
23488        cx: &mut App,
23489    ) -> Vec<Range<BufferRow>> {
23490        self.read(cx).lsp_store().update(cx, |lsp_store, cx| {
23491            lsp_store.applicable_inlay_chunks(buffer, ranges, cx)
23492        })
23493    }
23494
23495    fn invalidate_inlay_hints(&self, for_buffers: &HashSet<BufferId>, cx: &mut App) {
23496        self.read(cx).lsp_store().update(cx, |lsp_store, _| {
23497            lsp_store.invalidate_inlay_hints(for_buffers)
23498        });
23499    }
23500
23501    fn inlay_hints(
23502        &self,
23503        invalidate: InvalidationStrategy,
23504        buffer: Entity<Buffer>,
23505        ranges: Vec<Range<text::Anchor>>,
23506        known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
23507        cx: &mut App,
23508    ) -> Option<HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>>> {
23509        Some(self.read(cx).lsp_store().update(cx, |lsp_store, cx| {
23510            lsp_store.inlay_hints(invalidate, buffer, ranges, known_chunks, cx)
23511        }))
23512    }
23513
23514    fn range_for_rename(
23515        &self,
23516        buffer: &Entity<Buffer>,
23517        position: text::Anchor,
23518        cx: &mut App,
23519    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
23520        Some(self.update(cx, |project, cx| {
23521            let buffer = buffer.clone();
23522            let task = project.prepare_rename(buffer.clone(), position, cx);
23523            cx.spawn(async move |_, cx| {
23524                Ok(match task.await? {
23525                    PrepareRenameResponse::Success(range) => Some(range),
23526                    PrepareRenameResponse::InvalidPosition => None,
23527                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
23528                        // Fallback on using TreeSitter info to determine identifier range
23529                        buffer.read_with(cx, |buffer, _| {
23530                            let snapshot = buffer.snapshot();
23531                            let (range, kind) = snapshot.surrounding_word(position, None);
23532                            if kind != Some(CharKind::Word) {
23533                                return None;
23534                            }
23535                            Some(
23536                                snapshot.anchor_before(range.start)
23537                                    ..snapshot.anchor_after(range.end),
23538                            )
23539                        })?
23540                    }
23541                })
23542            })
23543        }))
23544    }
23545
23546    fn perform_rename(
23547        &self,
23548        buffer: &Entity<Buffer>,
23549        position: text::Anchor,
23550        new_name: String,
23551        cx: &mut App,
23552    ) -> Option<Task<Result<ProjectTransaction>>> {
23553        Some(self.update(cx, |project, cx| {
23554            project.perform_rename(buffer.clone(), position, new_name, cx)
23555        }))
23556    }
23557}
23558
23559fn consume_contiguous_rows(
23560    contiguous_row_selections: &mut Vec<Selection<Point>>,
23561    selection: &Selection<Point>,
23562    display_map: &DisplaySnapshot,
23563    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
23564) -> (MultiBufferRow, MultiBufferRow) {
23565    contiguous_row_selections.push(selection.clone());
23566    let start_row = starting_row(selection, display_map);
23567    let mut end_row = ending_row(selection, display_map);
23568
23569    while let Some(next_selection) = selections.peek() {
23570        if next_selection.start.row <= end_row.0 {
23571            end_row = ending_row(next_selection, display_map);
23572            contiguous_row_selections.push(selections.next().unwrap().clone());
23573        } else {
23574            break;
23575        }
23576    }
23577    (start_row, end_row)
23578}
23579
23580fn starting_row(selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
23581    if selection.start.column > 0 {
23582        MultiBufferRow(display_map.prev_line_boundary(selection.start).0.row)
23583    } else {
23584        MultiBufferRow(selection.start.row)
23585    }
23586}
23587
23588fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
23589    if next_selection.end.column > 0 || next_selection.is_empty() {
23590        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
23591    } else {
23592        MultiBufferRow(next_selection.end.row)
23593    }
23594}
23595
23596impl EditorSnapshot {
23597    pub fn remote_selections_in_range<'a>(
23598        &'a self,
23599        range: &'a Range<Anchor>,
23600        collaboration_hub: &dyn CollaborationHub,
23601        cx: &'a App,
23602    ) -> impl 'a + Iterator<Item = RemoteSelection> {
23603        let participant_names = collaboration_hub.user_names(cx);
23604        let participant_indices = collaboration_hub.user_participant_indices(cx);
23605        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
23606        let collaborators_by_replica_id = collaborators_by_peer_id
23607            .values()
23608            .map(|collaborator| (collaborator.replica_id, collaborator))
23609            .collect::<HashMap<_, _>>();
23610        self.buffer_snapshot()
23611            .selections_in_range(range, false)
23612            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
23613                if replica_id == ReplicaId::AGENT {
23614                    Some(RemoteSelection {
23615                        replica_id,
23616                        selection,
23617                        cursor_shape,
23618                        line_mode,
23619                        collaborator_id: CollaboratorId::Agent,
23620                        user_name: Some("Agent".into()),
23621                        color: cx.theme().players().agent(),
23622                    })
23623                } else {
23624                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
23625                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
23626                    let user_name = participant_names.get(&collaborator.user_id).cloned();
23627                    Some(RemoteSelection {
23628                        replica_id,
23629                        selection,
23630                        cursor_shape,
23631                        line_mode,
23632                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
23633                        user_name,
23634                        color: if let Some(index) = participant_index {
23635                            cx.theme().players().color_for_participant(index.0)
23636                        } else {
23637                            cx.theme().players().absent()
23638                        },
23639                    })
23640                }
23641            })
23642    }
23643
23644    pub fn hunks_for_ranges(
23645        &self,
23646        ranges: impl IntoIterator<Item = Range<Point>>,
23647    ) -> Vec<MultiBufferDiffHunk> {
23648        let mut hunks = Vec::new();
23649        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
23650            HashMap::default();
23651        for query_range in ranges {
23652            let query_rows =
23653                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
23654            for hunk in self.buffer_snapshot().diff_hunks_in_range(
23655                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
23656            ) {
23657                // Include deleted hunks that are adjacent to the query range, because
23658                // otherwise they would be missed.
23659                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
23660                if hunk.status().is_deleted() {
23661                    intersects_range |= hunk.row_range.start == query_rows.end;
23662                    intersects_range |= hunk.row_range.end == query_rows.start;
23663                }
23664                if intersects_range {
23665                    if !processed_buffer_rows
23666                        .entry(hunk.buffer_id)
23667                        .or_default()
23668                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
23669                    {
23670                        continue;
23671                    }
23672                    hunks.push(hunk);
23673                }
23674            }
23675        }
23676
23677        hunks
23678    }
23679
23680    fn display_diff_hunks_for_rows<'a>(
23681        &'a self,
23682        display_rows: Range<DisplayRow>,
23683        folded_buffers: &'a HashSet<BufferId>,
23684    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
23685        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
23686        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
23687
23688        self.buffer_snapshot()
23689            .diff_hunks_in_range(buffer_start..buffer_end)
23690            .filter_map(|hunk| {
23691                if folded_buffers.contains(&hunk.buffer_id) {
23692                    return None;
23693                }
23694
23695                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
23696                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
23697
23698                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
23699                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
23700
23701                let display_hunk = if hunk_display_start.column() != 0 {
23702                    DisplayDiffHunk::Folded {
23703                        display_row: hunk_display_start.row(),
23704                    }
23705                } else {
23706                    let mut end_row = hunk_display_end.row();
23707                    if hunk_display_end.column() > 0 {
23708                        end_row.0 += 1;
23709                    }
23710                    let is_created_file = hunk.is_created_file();
23711                    DisplayDiffHunk::Unfolded {
23712                        status: hunk.status(),
23713                        diff_base_byte_range: hunk.diff_base_byte_range,
23714                        display_row_range: hunk_display_start.row()..end_row,
23715                        multi_buffer_range: Anchor::range_in_buffer(
23716                            hunk.excerpt_id,
23717                            hunk.buffer_id,
23718                            hunk.buffer_range,
23719                        ),
23720                        is_created_file,
23721                    }
23722                };
23723
23724                Some(display_hunk)
23725            })
23726    }
23727
23728    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
23729        self.display_snapshot
23730            .buffer_snapshot()
23731            .language_at(position)
23732    }
23733
23734    pub fn is_focused(&self) -> bool {
23735        self.is_focused
23736    }
23737
23738    pub fn placeholder_text(&self) -> Option<String> {
23739        self.placeholder_display_snapshot
23740            .as_ref()
23741            .map(|display_map| display_map.text())
23742    }
23743
23744    pub fn scroll_position(&self) -> gpui::Point<ScrollOffset> {
23745        self.scroll_anchor.scroll_position(&self.display_snapshot)
23746    }
23747
23748    fn gutter_dimensions(
23749        &self,
23750        font_id: FontId,
23751        font_size: Pixels,
23752        max_line_number_width: Pixels,
23753        cx: &App,
23754    ) -> Option<GutterDimensions> {
23755        if !self.show_gutter {
23756            return None;
23757        }
23758
23759        let ch_width = cx.text_system().ch_width(font_id, font_size).log_err()?;
23760        let ch_advance = cx.text_system().ch_advance(font_id, font_size).log_err()?;
23761
23762        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
23763            matches!(
23764                ProjectSettings::get_global(cx).git.git_gutter,
23765                GitGutterSetting::TrackedFiles
23766            )
23767        });
23768        let gutter_settings = EditorSettings::get_global(cx).gutter;
23769        let show_line_numbers = self
23770            .show_line_numbers
23771            .unwrap_or(gutter_settings.line_numbers);
23772        let line_gutter_width = if show_line_numbers {
23773            // Avoid flicker-like gutter resizes when the line number gains another digit by
23774            // only resizing the gutter on files with > 10**min_line_number_digits lines.
23775            let min_width_for_number_on_gutter =
23776                ch_advance * gutter_settings.min_line_number_digits as f32;
23777            max_line_number_width.max(min_width_for_number_on_gutter)
23778        } else {
23779            0.0.into()
23780        };
23781
23782        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
23783        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
23784
23785        let git_blame_entries_width =
23786            self.git_blame_gutter_max_author_length
23787                .map(|max_author_length| {
23788                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
23789                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
23790
23791                    /// The number of characters to dedicate to gaps and margins.
23792                    const SPACING_WIDTH: usize = 4;
23793
23794                    let max_char_count = max_author_length.min(renderer.max_author_length())
23795                        + ::git::SHORT_SHA_LENGTH
23796                        + MAX_RELATIVE_TIMESTAMP.len()
23797                        + SPACING_WIDTH;
23798
23799                    ch_advance * max_char_count
23800                });
23801
23802        let is_singleton = self.buffer_snapshot().is_singleton();
23803
23804        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
23805        left_padding += if !is_singleton {
23806            ch_width * 4.0
23807        } else if show_runnables || show_breakpoints {
23808            ch_width * 3.0
23809        } else if show_git_gutter && show_line_numbers {
23810            ch_width * 2.0
23811        } else if show_git_gutter || show_line_numbers {
23812            ch_width
23813        } else {
23814            px(0.)
23815        };
23816
23817        let shows_folds = is_singleton && gutter_settings.folds;
23818
23819        let right_padding = if shows_folds && show_line_numbers {
23820            ch_width * 4.0
23821        } else if shows_folds || (!is_singleton && show_line_numbers) {
23822            ch_width * 3.0
23823        } else if show_line_numbers {
23824            ch_width
23825        } else {
23826            px(0.)
23827        };
23828
23829        Some(GutterDimensions {
23830            left_padding,
23831            right_padding,
23832            width: line_gutter_width + left_padding + right_padding,
23833            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
23834            git_blame_entries_width,
23835        })
23836    }
23837
23838    pub fn render_crease_toggle(
23839        &self,
23840        buffer_row: MultiBufferRow,
23841        row_contains_cursor: bool,
23842        editor: Entity<Editor>,
23843        window: &mut Window,
23844        cx: &mut App,
23845    ) -> Option<AnyElement> {
23846        let folded = self.is_line_folded(buffer_row);
23847        let mut is_foldable = false;
23848
23849        if let Some(crease) = self
23850            .crease_snapshot
23851            .query_row(buffer_row, self.buffer_snapshot())
23852        {
23853            is_foldable = true;
23854            match crease {
23855                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
23856                    if let Some(render_toggle) = render_toggle {
23857                        let toggle_callback =
23858                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
23859                                if folded {
23860                                    editor.update(cx, |editor, cx| {
23861                                        editor.fold_at(buffer_row, window, cx)
23862                                    });
23863                                } else {
23864                                    editor.update(cx, |editor, cx| {
23865                                        editor.unfold_at(buffer_row, window, cx)
23866                                    });
23867                                }
23868                            });
23869                        return Some((render_toggle)(
23870                            buffer_row,
23871                            folded,
23872                            toggle_callback,
23873                            window,
23874                            cx,
23875                        ));
23876                    }
23877                }
23878            }
23879        }
23880
23881        is_foldable |= self.starts_indent(buffer_row);
23882
23883        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
23884            Some(
23885                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
23886                    .toggle_state(folded)
23887                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
23888                        if folded {
23889                            this.unfold_at(buffer_row, window, cx);
23890                        } else {
23891                            this.fold_at(buffer_row, window, cx);
23892                        }
23893                    }))
23894                    .into_any_element(),
23895            )
23896        } else {
23897            None
23898        }
23899    }
23900
23901    pub fn render_crease_trailer(
23902        &self,
23903        buffer_row: MultiBufferRow,
23904        window: &mut Window,
23905        cx: &mut App,
23906    ) -> Option<AnyElement> {
23907        let folded = self.is_line_folded(buffer_row);
23908        if let Crease::Inline { render_trailer, .. } = self
23909            .crease_snapshot
23910            .query_row(buffer_row, self.buffer_snapshot())?
23911        {
23912            let render_trailer = render_trailer.as_ref()?;
23913            Some(render_trailer(buffer_row, folded, window, cx))
23914        } else {
23915            None
23916        }
23917    }
23918}
23919
23920impl Deref for EditorSnapshot {
23921    type Target = DisplaySnapshot;
23922
23923    fn deref(&self) -> &Self::Target {
23924        &self.display_snapshot
23925    }
23926}
23927
23928#[derive(Clone, Debug, PartialEq, Eq)]
23929pub enum EditorEvent {
23930    InputIgnored {
23931        text: Arc<str>,
23932    },
23933    InputHandled {
23934        utf16_range_to_replace: Option<Range<isize>>,
23935        text: Arc<str>,
23936    },
23937    ExcerptsAdded {
23938        buffer: Entity<Buffer>,
23939        predecessor: ExcerptId,
23940        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
23941    },
23942    ExcerptsRemoved {
23943        ids: Vec<ExcerptId>,
23944        removed_buffer_ids: Vec<BufferId>,
23945    },
23946    BufferFoldToggled {
23947        ids: Vec<ExcerptId>,
23948        folded: bool,
23949    },
23950    ExcerptsEdited {
23951        ids: Vec<ExcerptId>,
23952    },
23953    ExcerptsExpanded {
23954        ids: Vec<ExcerptId>,
23955    },
23956    BufferEdited,
23957    Edited {
23958        transaction_id: clock::Lamport,
23959    },
23960    Reparsed(BufferId),
23961    Focused,
23962    FocusedIn,
23963    Blurred,
23964    DirtyChanged,
23965    Saved,
23966    TitleChanged,
23967    SelectionsChanged {
23968        local: bool,
23969    },
23970    ScrollPositionChanged {
23971        local: bool,
23972        autoscroll: bool,
23973    },
23974    TransactionUndone {
23975        transaction_id: clock::Lamport,
23976    },
23977    TransactionBegun {
23978        transaction_id: clock::Lamport,
23979    },
23980    CursorShapeChanged,
23981    BreadcrumbsChanged,
23982    PushedToNavHistory {
23983        anchor: Anchor,
23984        is_deactivate: bool,
23985    },
23986}
23987
23988impl EventEmitter<EditorEvent> for Editor {}
23989
23990impl Focusable for Editor {
23991    fn focus_handle(&self, _cx: &App) -> FocusHandle {
23992        self.focus_handle.clone()
23993    }
23994}
23995
23996impl Render for Editor {
23997    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23998        let settings = ThemeSettings::get_global(cx);
23999
24000        let mut text_style = match self.mode {
24001            EditorMode::SingleLine | EditorMode::AutoHeight { .. } => TextStyle {
24002                color: cx.theme().colors().editor_foreground,
24003                font_family: settings.ui_font.family.clone(),
24004                font_features: settings.ui_font.features.clone(),
24005                font_fallbacks: settings.ui_font.fallbacks.clone(),
24006                font_size: rems(0.875).into(),
24007                font_weight: settings.ui_font.weight,
24008                line_height: relative(settings.buffer_line_height.value()),
24009                ..Default::default()
24010            },
24011            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
24012                color: cx.theme().colors().editor_foreground,
24013                font_family: settings.buffer_font.family.clone(),
24014                font_features: settings.buffer_font.features.clone(),
24015                font_fallbacks: settings.buffer_font.fallbacks.clone(),
24016                font_size: settings.buffer_font_size(cx).into(),
24017                font_weight: settings.buffer_font.weight,
24018                line_height: relative(settings.buffer_line_height.value()),
24019                ..Default::default()
24020            },
24021        };
24022        if let Some(text_style_refinement) = &self.text_style_refinement {
24023            text_style.refine(text_style_refinement)
24024        }
24025
24026        let background = match self.mode {
24027            EditorMode::SingleLine => cx.theme().system().transparent,
24028            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
24029            EditorMode::Full { .. } => cx.theme().colors().editor_background,
24030            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
24031        };
24032
24033        EditorElement::new(
24034            &cx.entity(),
24035            EditorStyle {
24036                background,
24037                border: cx.theme().colors().border,
24038                local_player: cx.theme().players().local(),
24039                text: text_style,
24040                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
24041                syntax: cx.theme().syntax().clone(),
24042                status: cx.theme().status().clone(),
24043                inlay_hints_style: make_inlay_hints_style(cx),
24044                edit_prediction_styles: make_suggestion_styles(cx),
24045                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
24046                show_underlines: self.diagnostics_enabled(),
24047            },
24048        )
24049    }
24050}
24051
24052impl EntityInputHandler for Editor {
24053    fn text_for_range(
24054        &mut self,
24055        range_utf16: Range<usize>,
24056        adjusted_range: &mut Option<Range<usize>>,
24057        _: &mut Window,
24058        cx: &mut Context<Self>,
24059    ) -> Option<String> {
24060        let snapshot = self.buffer.read(cx).read(cx);
24061        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
24062        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
24063        if (start.0..end.0) != range_utf16 {
24064            adjusted_range.replace(start.0..end.0);
24065        }
24066        Some(snapshot.text_for_range(start..end).collect())
24067    }
24068
24069    fn selected_text_range(
24070        &mut self,
24071        ignore_disabled_input: bool,
24072        _: &mut Window,
24073        cx: &mut Context<Self>,
24074    ) -> Option<UTF16Selection> {
24075        // Prevent the IME menu from appearing when holding down an alphabetic key
24076        // while input is disabled.
24077        if !ignore_disabled_input && !self.input_enabled {
24078            return None;
24079        }
24080
24081        let selection = self
24082            .selections
24083            .newest::<OffsetUtf16>(&self.display_snapshot(cx));
24084        let range = selection.range();
24085
24086        Some(UTF16Selection {
24087            range: range.start.0..range.end.0,
24088            reversed: selection.reversed,
24089        })
24090    }
24091
24092    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
24093        let snapshot = self.buffer.read(cx).read(cx);
24094        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
24095        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
24096    }
24097
24098    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
24099        self.clear_highlights::<InputComposition>(cx);
24100        self.ime_transaction.take();
24101    }
24102
24103    fn replace_text_in_range(
24104        &mut self,
24105        range_utf16: Option<Range<usize>>,
24106        text: &str,
24107        window: &mut Window,
24108        cx: &mut Context<Self>,
24109    ) {
24110        if !self.input_enabled {
24111            cx.emit(EditorEvent::InputIgnored { text: text.into() });
24112            return;
24113        }
24114
24115        self.transact(window, cx, |this, window, cx| {
24116            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
24117                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
24118                Some(this.selection_replacement_ranges(range_utf16, cx))
24119            } else {
24120                this.marked_text_ranges(cx)
24121            };
24122
24123            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
24124                let newest_selection_id = this.selections.newest_anchor().id;
24125                this.selections
24126                    .all::<OffsetUtf16>(&this.display_snapshot(cx))
24127                    .iter()
24128                    .zip(ranges_to_replace.iter())
24129                    .find_map(|(selection, range)| {
24130                        if selection.id == newest_selection_id {
24131                            Some(
24132                                (range.start.0 as isize - selection.head().0 as isize)
24133                                    ..(range.end.0 as isize - selection.head().0 as isize),
24134                            )
24135                        } else {
24136                            None
24137                        }
24138                    })
24139            });
24140
24141            cx.emit(EditorEvent::InputHandled {
24142                utf16_range_to_replace: range_to_replace,
24143                text: text.into(),
24144            });
24145
24146            if let Some(new_selected_ranges) = new_selected_ranges {
24147                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
24148                    selections.select_ranges(new_selected_ranges)
24149                });
24150                this.backspace(&Default::default(), window, cx);
24151            }
24152
24153            this.handle_input(text, window, cx);
24154        });
24155
24156        if let Some(transaction) = self.ime_transaction {
24157            self.buffer.update(cx, |buffer, cx| {
24158                buffer.group_until_transaction(transaction, cx);
24159            });
24160        }
24161
24162        self.unmark_text(window, cx);
24163    }
24164
24165    fn replace_and_mark_text_in_range(
24166        &mut self,
24167        range_utf16: Option<Range<usize>>,
24168        text: &str,
24169        new_selected_range_utf16: Option<Range<usize>>,
24170        window: &mut Window,
24171        cx: &mut Context<Self>,
24172    ) {
24173        if !self.input_enabled {
24174            return;
24175        }
24176
24177        let transaction = self.transact(window, cx, |this, window, cx| {
24178            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
24179                let snapshot = this.buffer.read(cx).read(cx);
24180                if let Some(relative_range_utf16) = range_utf16.as_ref() {
24181                    for marked_range in &mut marked_ranges {
24182                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
24183                        marked_range.start.0 += relative_range_utf16.start;
24184                        marked_range.start =
24185                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
24186                        marked_range.end =
24187                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
24188                    }
24189                }
24190                Some(marked_ranges)
24191            } else if let Some(range_utf16) = range_utf16 {
24192                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
24193                Some(this.selection_replacement_ranges(range_utf16, cx))
24194            } else {
24195                None
24196            };
24197
24198            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
24199                let newest_selection_id = this.selections.newest_anchor().id;
24200                this.selections
24201                    .all::<OffsetUtf16>(&this.display_snapshot(cx))
24202                    .iter()
24203                    .zip(ranges_to_replace.iter())
24204                    .find_map(|(selection, range)| {
24205                        if selection.id == newest_selection_id {
24206                            Some(
24207                                (range.start.0 as isize - selection.head().0 as isize)
24208                                    ..(range.end.0 as isize - selection.head().0 as isize),
24209                            )
24210                        } else {
24211                            None
24212                        }
24213                    })
24214            });
24215
24216            cx.emit(EditorEvent::InputHandled {
24217                utf16_range_to_replace: range_to_replace,
24218                text: text.into(),
24219            });
24220
24221            if let Some(ranges) = ranges_to_replace {
24222                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
24223                    s.select_ranges(ranges)
24224                });
24225            }
24226
24227            let marked_ranges = {
24228                let snapshot = this.buffer.read(cx).read(cx);
24229                this.selections
24230                    .disjoint_anchors_arc()
24231                    .iter()
24232                    .map(|selection| {
24233                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
24234                    })
24235                    .collect::<Vec<_>>()
24236            };
24237
24238            if text.is_empty() {
24239                this.unmark_text(window, cx);
24240            } else {
24241                this.highlight_text::<InputComposition>(
24242                    marked_ranges.clone(),
24243                    HighlightStyle {
24244                        underline: Some(UnderlineStyle {
24245                            thickness: px(1.),
24246                            color: None,
24247                            wavy: false,
24248                        }),
24249                        ..Default::default()
24250                    },
24251                    cx,
24252                );
24253            }
24254
24255            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
24256            let use_autoclose = this.use_autoclose;
24257            let use_auto_surround = this.use_auto_surround;
24258            this.set_use_autoclose(false);
24259            this.set_use_auto_surround(false);
24260            this.handle_input(text, window, cx);
24261            this.set_use_autoclose(use_autoclose);
24262            this.set_use_auto_surround(use_auto_surround);
24263
24264            if let Some(new_selected_range) = new_selected_range_utf16 {
24265                let snapshot = this.buffer.read(cx).read(cx);
24266                let new_selected_ranges = marked_ranges
24267                    .into_iter()
24268                    .map(|marked_range| {
24269                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
24270                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
24271                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
24272                        snapshot.clip_offset_utf16(new_start, Bias::Left)
24273                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
24274                    })
24275                    .collect::<Vec<_>>();
24276
24277                drop(snapshot);
24278                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
24279                    selections.select_ranges(new_selected_ranges)
24280                });
24281            }
24282        });
24283
24284        self.ime_transaction = self.ime_transaction.or(transaction);
24285        if let Some(transaction) = self.ime_transaction {
24286            self.buffer.update(cx, |buffer, cx| {
24287                buffer.group_until_transaction(transaction, cx);
24288            });
24289        }
24290
24291        if self.text_highlights::<InputComposition>(cx).is_none() {
24292            self.ime_transaction.take();
24293        }
24294    }
24295
24296    fn bounds_for_range(
24297        &mut self,
24298        range_utf16: Range<usize>,
24299        element_bounds: gpui::Bounds<Pixels>,
24300        window: &mut Window,
24301        cx: &mut Context<Self>,
24302    ) -> Option<gpui::Bounds<Pixels>> {
24303        let text_layout_details = self.text_layout_details(window);
24304        let CharacterDimensions {
24305            em_width,
24306            em_advance,
24307            line_height,
24308        } = self.character_dimensions(window);
24309
24310        let snapshot = self.snapshot(window, cx);
24311        let scroll_position = snapshot.scroll_position();
24312        let scroll_left = scroll_position.x * ScrollOffset::from(em_advance);
24313
24314        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
24315        let x = Pixels::from(
24316            ScrollOffset::from(
24317                snapshot.x_for_display_point(start, &text_layout_details)
24318                    + self.gutter_dimensions.full_width(),
24319            ) - scroll_left,
24320        );
24321        let y = line_height * (start.row().as_f64() - scroll_position.y) as f32;
24322
24323        Some(Bounds {
24324            origin: element_bounds.origin + point(x, y),
24325            size: size(em_width, line_height),
24326        })
24327    }
24328
24329    fn character_index_for_point(
24330        &mut self,
24331        point: gpui::Point<Pixels>,
24332        _window: &mut Window,
24333        _cx: &mut Context<Self>,
24334    ) -> Option<usize> {
24335        let position_map = self.last_position_map.as_ref()?;
24336        if !position_map.text_hitbox.contains(&point) {
24337            return None;
24338        }
24339        let display_point = position_map.point_for_position(point).previous_valid;
24340        let anchor = position_map
24341            .snapshot
24342            .display_point_to_anchor(display_point, Bias::Left);
24343        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot());
24344        Some(utf16_offset.0)
24345    }
24346
24347    fn accepts_text_input(&self, _window: &mut Window, _cx: &mut Context<Self>) -> bool {
24348        self.input_enabled
24349    }
24350}
24351
24352trait SelectionExt {
24353    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
24354    fn spanned_rows(
24355        &self,
24356        include_end_if_at_line_start: bool,
24357        map: &DisplaySnapshot,
24358    ) -> Range<MultiBufferRow>;
24359}
24360
24361impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
24362    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
24363        let start = self
24364            .start
24365            .to_point(map.buffer_snapshot())
24366            .to_display_point(map);
24367        let end = self
24368            .end
24369            .to_point(map.buffer_snapshot())
24370            .to_display_point(map);
24371        if self.reversed {
24372            end..start
24373        } else {
24374            start..end
24375        }
24376    }
24377
24378    fn spanned_rows(
24379        &self,
24380        include_end_if_at_line_start: bool,
24381        map: &DisplaySnapshot,
24382    ) -> Range<MultiBufferRow> {
24383        let start = self.start.to_point(map.buffer_snapshot());
24384        let mut end = self.end.to_point(map.buffer_snapshot());
24385        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
24386            end.row -= 1;
24387        }
24388
24389        let buffer_start = map.prev_line_boundary(start).0;
24390        let buffer_end = map.next_line_boundary(end).0;
24391        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
24392    }
24393}
24394
24395impl<T: InvalidationRegion> InvalidationStack<T> {
24396    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
24397    where
24398        S: Clone + ToOffset,
24399    {
24400        while let Some(region) = self.last() {
24401            let all_selections_inside_invalidation_ranges =
24402                if selections.len() == region.ranges().len() {
24403                    selections
24404                        .iter()
24405                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
24406                        .all(|(selection, invalidation_range)| {
24407                            let head = selection.head().to_offset(buffer);
24408                            invalidation_range.start <= head && invalidation_range.end >= head
24409                        })
24410                } else {
24411                    false
24412                };
24413
24414            if all_selections_inside_invalidation_ranges {
24415                break;
24416            } else {
24417                self.pop();
24418            }
24419        }
24420    }
24421}
24422
24423impl<T> Default for InvalidationStack<T> {
24424    fn default() -> Self {
24425        Self(Default::default())
24426    }
24427}
24428
24429impl<T> Deref for InvalidationStack<T> {
24430    type Target = Vec<T>;
24431
24432    fn deref(&self) -> &Self::Target {
24433        &self.0
24434    }
24435}
24436
24437impl<T> DerefMut for InvalidationStack<T> {
24438    fn deref_mut(&mut self) -> &mut Self::Target {
24439        &mut self.0
24440    }
24441}
24442
24443impl InvalidationRegion for SnippetState {
24444    fn ranges(&self) -> &[Range<Anchor>] {
24445        &self.ranges[self.active_index]
24446    }
24447}
24448
24449fn edit_prediction_edit_text(
24450    current_snapshot: &BufferSnapshot,
24451    edits: &[(Range<Anchor>, impl AsRef<str>)],
24452    edit_preview: &EditPreview,
24453    include_deletions: bool,
24454    cx: &App,
24455) -> HighlightedText {
24456    let edits = edits
24457        .iter()
24458        .map(|(anchor, text)| (anchor.start.text_anchor..anchor.end.text_anchor, text))
24459        .collect::<Vec<_>>();
24460
24461    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
24462}
24463
24464fn edit_prediction_fallback_text(edits: &[(Range<Anchor>, Arc<str>)], cx: &App) -> HighlightedText {
24465    // Fallback for providers that don't provide edit_preview (like Copilot/Supermaven)
24466    // Just show the raw edit text with basic styling
24467    let mut text = String::new();
24468    let mut highlights = Vec::new();
24469
24470    let insertion_highlight_style = HighlightStyle {
24471        color: Some(cx.theme().colors().text),
24472        ..Default::default()
24473    };
24474
24475    for (_, edit_text) in edits {
24476        let start_offset = text.len();
24477        text.push_str(edit_text);
24478        let end_offset = text.len();
24479
24480        if start_offset < end_offset {
24481            highlights.push((start_offset..end_offset, insertion_highlight_style));
24482        }
24483    }
24484
24485    HighlightedText {
24486        text: text.into(),
24487        highlights,
24488    }
24489}
24490
24491pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
24492    match severity {
24493        lsp::DiagnosticSeverity::ERROR => colors.error,
24494        lsp::DiagnosticSeverity::WARNING => colors.warning,
24495        lsp::DiagnosticSeverity::INFORMATION => colors.info,
24496        lsp::DiagnosticSeverity::HINT => colors.info,
24497        _ => colors.ignored,
24498    }
24499}
24500
24501pub fn styled_runs_for_code_label<'a>(
24502    label: &'a CodeLabel,
24503    syntax_theme: &'a theme::SyntaxTheme,
24504) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
24505    let fade_out = HighlightStyle {
24506        fade_out: Some(0.35),
24507        ..Default::default()
24508    };
24509
24510    let mut prev_end = label.filter_range.end;
24511    label
24512        .runs
24513        .iter()
24514        .enumerate()
24515        .flat_map(move |(ix, (range, highlight_id))| {
24516            let style = if let Some(style) = highlight_id.style(syntax_theme) {
24517                style
24518            } else {
24519                return Default::default();
24520            };
24521            let muted_style = style.highlight(fade_out);
24522
24523            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
24524            if range.start >= label.filter_range.end {
24525                if range.start > prev_end {
24526                    runs.push((prev_end..range.start, fade_out));
24527                }
24528                runs.push((range.clone(), muted_style));
24529            } else if range.end <= label.filter_range.end {
24530                runs.push((range.clone(), style));
24531            } else {
24532                runs.push((range.start..label.filter_range.end, style));
24533                runs.push((label.filter_range.end..range.end, muted_style));
24534            }
24535            prev_end = cmp::max(prev_end, range.end);
24536
24537            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
24538                runs.push((prev_end..label.text.len(), fade_out));
24539            }
24540
24541            runs
24542        })
24543}
24544
24545pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
24546    let mut prev_index = 0;
24547    let mut prev_codepoint: Option<char> = None;
24548    text.char_indices()
24549        .chain([(text.len(), '\0')])
24550        .filter_map(move |(index, codepoint)| {
24551            let prev_codepoint = prev_codepoint.replace(codepoint)?;
24552            let is_boundary = index == text.len()
24553                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
24554                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
24555            if is_boundary {
24556                let chunk = &text[prev_index..index];
24557                prev_index = index;
24558                Some(chunk)
24559            } else {
24560                None
24561            }
24562        })
24563}
24564
24565pub trait RangeToAnchorExt: Sized {
24566    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
24567
24568    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
24569        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot());
24570        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
24571    }
24572}
24573
24574impl<T: ToOffset> RangeToAnchorExt for Range<T> {
24575    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
24576        let start_offset = self.start.to_offset(snapshot);
24577        let end_offset = self.end.to_offset(snapshot);
24578        if start_offset == end_offset {
24579            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
24580        } else {
24581            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
24582        }
24583    }
24584}
24585
24586pub trait RowExt {
24587    fn as_f64(&self) -> f64;
24588
24589    fn next_row(&self) -> Self;
24590
24591    fn previous_row(&self) -> Self;
24592
24593    fn minus(&self, other: Self) -> u32;
24594}
24595
24596impl RowExt for DisplayRow {
24597    fn as_f64(&self) -> f64 {
24598        self.0 as _
24599    }
24600
24601    fn next_row(&self) -> Self {
24602        Self(self.0 + 1)
24603    }
24604
24605    fn previous_row(&self) -> Self {
24606        Self(self.0.saturating_sub(1))
24607    }
24608
24609    fn minus(&self, other: Self) -> u32 {
24610        self.0 - other.0
24611    }
24612}
24613
24614impl RowExt for MultiBufferRow {
24615    fn as_f64(&self) -> f64 {
24616        self.0 as _
24617    }
24618
24619    fn next_row(&self) -> Self {
24620        Self(self.0 + 1)
24621    }
24622
24623    fn previous_row(&self) -> Self {
24624        Self(self.0.saturating_sub(1))
24625    }
24626
24627    fn minus(&self, other: Self) -> u32 {
24628        self.0 - other.0
24629    }
24630}
24631
24632trait RowRangeExt {
24633    type Row;
24634
24635    fn len(&self) -> usize;
24636
24637    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
24638}
24639
24640impl RowRangeExt for Range<MultiBufferRow> {
24641    type Row = MultiBufferRow;
24642
24643    fn len(&self) -> usize {
24644        (self.end.0 - self.start.0) as usize
24645    }
24646
24647    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
24648        (self.start.0..self.end.0).map(MultiBufferRow)
24649    }
24650}
24651
24652impl RowRangeExt for Range<DisplayRow> {
24653    type Row = DisplayRow;
24654
24655    fn len(&self) -> usize {
24656        (self.end.0 - self.start.0) as usize
24657    }
24658
24659    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
24660        (self.start.0..self.end.0).map(DisplayRow)
24661    }
24662}
24663
24664/// If select range has more than one line, we
24665/// just point the cursor to range.start.
24666fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
24667    if range.start.row == range.end.row {
24668        range
24669    } else {
24670        range.start..range.start
24671    }
24672}
24673pub struct KillRing(ClipboardItem);
24674impl Global for KillRing {}
24675
24676const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
24677
24678enum BreakpointPromptEditAction {
24679    Log,
24680    Condition,
24681    HitCondition,
24682}
24683
24684struct BreakpointPromptEditor {
24685    pub(crate) prompt: Entity<Editor>,
24686    editor: WeakEntity<Editor>,
24687    breakpoint_anchor: Anchor,
24688    breakpoint: Breakpoint,
24689    edit_action: BreakpointPromptEditAction,
24690    block_ids: HashSet<CustomBlockId>,
24691    editor_margins: Arc<Mutex<EditorMargins>>,
24692    _subscriptions: Vec<Subscription>,
24693}
24694
24695impl BreakpointPromptEditor {
24696    const MAX_LINES: u8 = 4;
24697
24698    fn new(
24699        editor: WeakEntity<Editor>,
24700        breakpoint_anchor: Anchor,
24701        breakpoint: Breakpoint,
24702        edit_action: BreakpointPromptEditAction,
24703        window: &mut Window,
24704        cx: &mut Context<Self>,
24705    ) -> Self {
24706        let base_text = match edit_action {
24707            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
24708            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
24709            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
24710        }
24711        .map(|msg| msg.to_string())
24712        .unwrap_or_default();
24713
24714        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
24715        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
24716
24717        let prompt = cx.new(|cx| {
24718            let mut prompt = Editor::new(
24719                EditorMode::AutoHeight {
24720                    min_lines: 1,
24721                    max_lines: Some(Self::MAX_LINES as usize),
24722                },
24723                buffer,
24724                None,
24725                window,
24726                cx,
24727            );
24728            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
24729            prompt.set_show_cursor_when_unfocused(false, cx);
24730            prompt.set_placeholder_text(
24731                match edit_action {
24732                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
24733                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
24734                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
24735                },
24736                window,
24737                cx,
24738            );
24739
24740            prompt
24741        });
24742
24743        Self {
24744            prompt,
24745            editor,
24746            breakpoint_anchor,
24747            breakpoint,
24748            edit_action,
24749            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
24750            block_ids: Default::default(),
24751            _subscriptions: vec![],
24752        }
24753    }
24754
24755    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
24756        self.block_ids.extend(block_ids)
24757    }
24758
24759    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
24760        if let Some(editor) = self.editor.upgrade() {
24761            let message = self
24762                .prompt
24763                .read(cx)
24764                .buffer
24765                .read(cx)
24766                .as_singleton()
24767                .expect("A multi buffer in breakpoint prompt isn't possible")
24768                .read(cx)
24769                .as_rope()
24770                .to_string();
24771
24772            editor.update(cx, |editor, cx| {
24773                editor.edit_breakpoint_at_anchor(
24774                    self.breakpoint_anchor,
24775                    self.breakpoint.clone(),
24776                    match self.edit_action {
24777                        BreakpointPromptEditAction::Log => {
24778                            BreakpointEditAction::EditLogMessage(message.into())
24779                        }
24780                        BreakpointPromptEditAction::Condition => {
24781                            BreakpointEditAction::EditCondition(message.into())
24782                        }
24783                        BreakpointPromptEditAction::HitCondition => {
24784                            BreakpointEditAction::EditHitCondition(message.into())
24785                        }
24786                    },
24787                    cx,
24788                );
24789
24790                editor.remove_blocks(self.block_ids.clone(), None, cx);
24791                cx.focus_self(window);
24792            });
24793        }
24794    }
24795
24796    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
24797        self.editor
24798            .update(cx, |editor, cx| {
24799                editor.remove_blocks(self.block_ids.clone(), None, cx);
24800                window.focus(&editor.focus_handle);
24801            })
24802            .log_err();
24803    }
24804
24805    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
24806        let settings = ThemeSettings::get_global(cx);
24807        let text_style = TextStyle {
24808            color: if self.prompt.read(cx).read_only(cx) {
24809                cx.theme().colors().text_disabled
24810            } else {
24811                cx.theme().colors().text
24812            },
24813            font_family: settings.buffer_font.family.clone(),
24814            font_fallbacks: settings.buffer_font.fallbacks.clone(),
24815            font_size: settings.buffer_font_size(cx).into(),
24816            font_weight: settings.buffer_font.weight,
24817            line_height: relative(settings.buffer_line_height.value()),
24818            ..Default::default()
24819        };
24820        EditorElement::new(
24821            &self.prompt,
24822            EditorStyle {
24823                background: cx.theme().colors().editor_background,
24824                local_player: cx.theme().players().local(),
24825                text: text_style,
24826                ..Default::default()
24827            },
24828        )
24829    }
24830}
24831
24832impl Render for BreakpointPromptEditor {
24833    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
24834        let editor_margins = *self.editor_margins.lock();
24835        let gutter_dimensions = editor_margins.gutter;
24836        h_flex()
24837            .key_context("Editor")
24838            .bg(cx.theme().colors().editor_background)
24839            .border_y_1()
24840            .border_color(cx.theme().status().info_border)
24841            .size_full()
24842            .py(window.line_height() / 2.5)
24843            .on_action(cx.listener(Self::confirm))
24844            .on_action(cx.listener(Self::cancel))
24845            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
24846            .child(div().flex_1().child(self.render_prompt_editor(cx)))
24847    }
24848}
24849
24850impl Focusable for BreakpointPromptEditor {
24851    fn focus_handle(&self, cx: &App) -> FocusHandle {
24852        self.prompt.focus_handle(cx)
24853    }
24854}
24855
24856fn all_edits_insertions_or_deletions(
24857    edits: &Vec<(Range<Anchor>, Arc<str>)>,
24858    snapshot: &MultiBufferSnapshot,
24859) -> bool {
24860    let mut all_insertions = true;
24861    let mut all_deletions = true;
24862
24863    for (range, new_text) in edits.iter() {
24864        let range_is_empty = range.to_offset(snapshot).is_empty();
24865        let text_is_empty = new_text.is_empty();
24866
24867        if range_is_empty != text_is_empty {
24868            if range_is_empty {
24869                all_deletions = false;
24870            } else {
24871                all_insertions = false;
24872            }
24873        } else {
24874            return false;
24875        }
24876
24877        if !all_insertions && !all_deletions {
24878            return false;
24879        }
24880    }
24881    all_insertions || all_deletions
24882}
24883
24884struct MissingEditPredictionKeybindingTooltip;
24885
24886impl Render for MissingEditPredictionKeybindingTooltip {
24887    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
24888        ui::tooltip_container(cx, |container, cx| {
24889            container
24890                .flex_shrink_0()
24891                .max_w_80()
24892                .min_h(rems_from_px(124.))
24893                .justify_between()
24894                .child(
24895                    v_flex()
24896                        .flex_1()
24897                        .text_ui_sm(cx)
24898                        .child(Label::new("Conflict with Accept Keybinding"))
24899                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
24900                )
24901                .child(
24902                    h_flex()
24903                        .pb_1()
24904                        .gap_1()
24905                        .items_end()
24906                        .w_full()
24907                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
24908                            window.dispatch_action(zed_actions::OpenKeymapFile.boxed_clone(), cx)
24909                        }))
24910                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
24911                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
24912                        })),
24913                )
24914        })
24915    }
24916}
24917
24918#[derive(Debug, Clone, Copy, PartialEq)]
24919pub struct LineHighlight {
24920    pub background: Background,
24921    pub border: Option<gpui::Hsla>,
24922    pub include_gutter: bool,
24923    pub type_id: Option<TypeId>,
24924}
24925
24926struct LineManipulationResult {
24927    pub new_text: String,
24928    pub line_count_before: usize,
24929    pub line_count_after: usize,
24930}
24931
24932fn render_diff_hunk_controls(
24933    row: u32,
24934    status: &DiffHunkStatus,
24935    hunk_range: Range<Anchor>,
24936    is_created_file: bool,
24937    line_height: Pixels,
24938    editor: &Entity<Editor>,
24939    _window: &mut Window,
24940    cx: &mut App,
24941) -> AnyElement {
24942    h_flex()
24943        .h(line_height)
24944        .mr_1()
24945        .gap_1()
24946        .px_0p5()
24947        .pb_1()
24948        .border_x_1()
24949        .border_b_1()
24950        .border_color(cx.theme().colors().border_variant)
24951        .rounded_b_lg()
24952        .bg(cx.theme().colors().editor_background)
24953        .gap_1()
24954        .block_mouse_except_scroll()
24955        .shadow_md()
24956        .child(if status.has_secondary_hunk() {
24957            Button::new(("stage", row as u64), "Stage")
24958                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
24959                .tooltip({
24960                    let focus_handle = editor.focus_handle(cx);
24961                    move |_window, cx| {
24962                        Tooltip::for_action_in(
24963                            "Stage Hunk",
24964                            &::git::ToggleStaged,
24965                            &focus_handle,
24966                            cx,
24967                        )
24968                    }
24969                })
24970                .on_click({
24971                    let editor = editor.clone();
24972                    move |_event, _window, cx| {
24973                        editor.update(cx, |editor, cx| {
24974                            editor.stage_or_unstage_diff_hunks(
24975                                true,
24976                                vec![hunk_range.start..hunk_range.start],
24977                                cx,
24978                            );
24979                        });
24980                    }
24981                })
24982        } else {
24983            Button::new(("unstage", row as u64), "Unstage")
24984                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
24985                .tooltip({
24986                    let focus_handle = editor.focus_handle(cx);
24987                    move |_window, cx| {
24988                        Tooltip::for_action_in(
24989                            "Unstage Hunk",
24990                            &::git::ToggleStaged,
24991                            &focus_handle,
24992                            cx,
24993                        )
24994                    }
24995                })
24996                .on_click({
24997                    let editor = editor.clone();
24998                    move |_event, _window, cx| {
24999                        editor.update(cx, |editor, cx| {
25000                            editor.stage_or_unstage_diff_hunks(
25001                                false,
25002                                vec![hunk_range.start..hunk_range.start],
25003                                cx,
25004                            );
25005                        });
25006                    }
25007                })
25008        })
25009        .child(
25010            Button::new(("restore", row as u64), "Restore")
25011                .tooltip({
25012                    let focus_handle = editor.focus_handle(cx);
25013                    move |_window, cx| {
25014                        Tooltip::for_action_in("Restore Hunk", &::git::Restore, &focus_handle, cx)
25015                    }
25016                })
25017                .on_click({
25018                    let editor = editor.clone();
25019                    move |_event, window, cx| {
25020                        editor.update(cx, |editor, cx| {
25021                            let snapshot = editor.snapshot(window, cx);
25022                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot());
25023                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
25024                        });
25025                    }
25026                })
25027                .disabled(is_created_file),
25028        )
25029        .when(
25030            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
25031            |el| {
25032                el.child(
25033                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
25034                        .shape(IconButtonShape::Square)
25035                        .icon_size(IconSize::Small)
25036                        // .disabled(!has_multiple_hunks)
25037                        .tooltip({
25038                            let focus_handle = editor.focus_handle(cx);
25039                            move |_window, cx| {
25040                                Tooltip::for_action_in("Next Hunk", &GoToHunk, &focus_handle, cx)
25041                            }
25042                        })
25043                        .on_click({
25044                            let editor = editor.clone();
25045                            move |_event, window, cx| {
25046                                editor.update(cx, |editor, cx| {
25047                                    let snapshot = editor.snapshot(window, cx);
25048                                    let position =
25049                                        hunk_range.end.to_point(&snapshot.buffer_snapshot());
25050                                    editor.go_to_hunk_before_or_after_position(
25051                                        &snapshot,
25052                                        position,
25053                                        Direction::Next,
25054                                        window,
25055                                        cx,
25056                                    );
25057                                    editor.expand_selected_diff_hunks(cx);
25058                                });
25059                            }
25060                        }),
25061                )
25062                .child(
25063                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
25064                        .shape(IconButtonShape::Square)
25065                        .icon_size(IconSize::Small)
25066                        // .disabled(!has_multiple_hunks)
25067                        .tooltip({
25068                            let focus_handle = editor.focus_handle(cx);
25069                            move |_window, cx| {
25070                                Tooltip::for_action_in(
25071                                    "Previous Hunk",
25072                                    &GoToPreviousHunk,
25073                                    &focus_handle,
25074                                    cx,
25075                                )
25076                            }
25077                        })
25078                        .on_click({
25079                            let editor = editor.clone();
25080                            move |_event, window, cx| {
25081                                editor.update(cx, |editor, cx| {
25082                                    let snapshot = editor.snapshot(window, cx);
25083                                    let point =
25084                                        hunk_range.start.to_point(&snapshot.buffer_snapshot());
25085                                    editor.go_to_hunk_before_or_after_position(
25086                                        &snapshot,
25087                                        point,
25088                                        Direction::Prev,
25089                                        window,
25090                                        cx,
25091                                    );
25092                                    editor.expand_selected_diff_hunks(cx);
25093                                });
25094                            }
25095                        }),
25096                )
25097            },
25098        )
25099        .into_any_element()
25100}
25101
25102pub fn multibuffer_context_lines(cx: &App) -> u32 {
25103    EditorSettings::try_get(cx)
25104        .map(|settings| settings.excerpt_context_lines)
25105        .unwrap_or(2)
25106        .min(32)
25107}